summaryrefslogtreecommitdiffstats
path: root/dom/tests/mochitest/localstorage
diff options
context:
space:
mode:
Diffstat (limited to 'dom/tests/mochitest/localstorage')
-rw-r--r--dom/tests/mochitest/localstorage/chrome.ini11
-rw-r--r--dom/tests/mochitest/localstorage/file_tryAccessSessionStorage.html10
-rw-r--r--dom/tests/mochitest/localstorage/frameChromeSlave.html9
-rw-r--r--dom/tests/mochitest/localstorage/frameKeySync.html51
-rw-r--r--dom/tests/mochitest/localstorage/frameLocalStorageCookieSettings.html26
-rw-r--r--dom/tests/mochitest/localstorage/frameLocalStorageSessionOnly.html8
-rw-r--r--dom/tests/mochitest/localstorage/frameMasterEqual.html56
-rw-r--r--dom/tests/mochitest/localstorage/frameMasterNotEqual.html47
-rw-r--r--dom/tests/mochitest/localstorage/frameOrder.html27
-rw-r--r--dom/tests/mochitest/localstorage/frameQuota.html97
-rw-r--r--dom/tests/mochitest/localstorage/frameQuotaSessionOnly.html101
-rw-r--r--dom/tests/mochitest/localstorage/frameReplace.html72
-rw-r--r--dom/tests/mochitest/localstorage/frameSlaveEqual.html51
-rw-r--r--dom/tests/mochitest/localstorage/frameSlaveNotEqual.html44
-rw-r--r--dom/tests/mochitest/localstorage/interOriginFrame.js53
-rw-r--r--dom/tests/mochitest/localstorage/interOriginTest.js41
-rw-r--r--dom/tests/mochitest/localstorage/interOriginTest2.js53
-rw-r--r--dom/tests/mochitest/localstorage/localStorageCommon.js131
-rw-r--r--dom/tests/mochitest/localstorage/mochitest.ini63
-rw-r--r--dom/tests/mochitest/localstorage/page_blank.html6
-rw-r--r--dom/tests/mochitest/localstorage/test_brokenUTF-16.html100
-rw-r--r--dom/tests/mochitest/localstorage/test_bug600307-DBOps.html178
-rw-r--r--dom/tests/mochitest/localstorage/test_bug746272-1.html32
-rw-r--r--dom/tests/mochitest/localstorage/test_bug746272-2.html31
-rw-r--r--dom/tests/mochitest/localstorage/test_cookieBlock.html53
-rw-r--r--dom/tests/mochitest/localstorage/test_embededNulls.html40
-rw-r--r--dom/tests/mochitest/localstorage/test_keySync.html33
-rw-r--r--dom/tests/mochitest/localstorage/test_localStorageBase.html247
-rw-r--r--dom/tests/mochitest/localstorage/test_localStorageBasePrivateBrowsing_perwindowpb.html256
-rw-r--r--dom/tests/mochitest/localstorage/test_localStorageBaseSessionOnly.html211
-rw-r--r--dom/tests/mochitest/localstorage/test_localStorageCookieSettings.html75
-rw-r--r--dom/tests/mochitest/localstorage/test_localStorageEnablePref.html65
-rw-r--r--dom/tests/mochitest/localstorage/test_localStorageFromChrome.xhtml60
-rw-r--r--dom/tests/mochitest/localstorage/test_localStorageKeyOrder.html73
-rw-r--r--dom/tests/mochitest/localstorage/test_localStorageOriginsDiff.html41
-rw-r--r--dom/tests/mochitest/localstorage/test_localStorageOriginsDomainDiffs.html41
-rw-r--r--dom/tests/mochitest/localstorage/test_localStorageOriginsEquals.html42
-rw-r--r--dom/tests/mochitest/localstorage/test_localStorageOriginsPortDiffs.html41
-rw-r--r--dom/tests/mochitest/localstorage/test_localStorageOriginsSchemaDiffs.html41
-rw-r--r--dom/tests/mochitest/localstorage/test_localStorageQuota.html136
-rw-r--r--dom/tests/mochitest/localstorage/test_localStorageQuotaPrivateBrowsing_perwindowpb.html189
-rw-r--r--dom/tests/mochitest/localstorage/test_localStorageQuotaSessionOnly.html134
-rw-r--r--dom/tests/mochitest/localstorage/test_localStorageQuotaSessionOnly2.html98
-rw-r--r--dom/tests/mochitest/localstorage/test_localStorageReplace.html80
-rw-r--r--dom/tests/mochitest/localstorage/test_storageConstructor.html35
-rw-r--r--dom/tests/mochitest/localstorage/windowProxy.html3
46 files changed, 3292 insertions, 0 deletions
diff --git a/dom/tests/mochitest/localstorage/chrome.ini b/dom/tests/mochitest/localstorage/chrome.ini
new file mode 100644
index 0000000000..6cc5562c00
--- /dev/null
+++ b/dom/tests/mochitest/localstorage/chrome.ini
@@ -0,0 +1,11 @@
+[DEFAULT]
+skip-if = os == 'android'
+support-files =
+ page_blank.html
+ frameQuota.html
+ interOriginFrame.js
+
+[test_localStorageBasePrivateBrowsing_perwindowpb.html]
+skip-if = true # bug 1156725
+[test_localStorageFromChrome.xhtml]
+[test_localStorageQuotaPrivateBrowsing_perwindowpb.html]
diff --git a/dom/tests/mochitest/localstorage/file_tryAccessSessionStorage.html b/dom/tests/mochitest/localstorage/file_tryAccessSessionStorage.html
new file mode 100644
index 0000000000..1def32a62a
--- /dev/null
+++ b/dom/tests/mochitest/localstorage/file_tryAccessSessionStorage.html
@@ -0,0 +1,10 @@
+<script>
+ try {
+ sessionStorage.setItem("am_i_blocked", "nope");
+ window.parent.postMessage('sessionStorage=true', '*');
+ document.body.innerHTML += 'yes';
+ } catch (ex) {
+ window.parent.postMessage('sessionStorage=false', '*');
+ document.body.innerHTML += 'no';
+ }
+</script>
diff --git a/dom/tests/mochitest/localstorage/frameChromeSlave.html b/dom/tests/mochitest/localstorage/frameChromeSlave.html
new file mode 100644
index 0000000000..fd87702e9d
--- /dev/null
+++ b/dom/tests/mochitest/localstorage/frameChromeSlave.html
@@ -0,0 +1,9 @@
+<html>
+<head>
+<body>
+ <span id="data"></span>
+ <script>
+ var span = document.getElementById("data");
+ span.innerHTML = localStorage.chromekey
+ </script>
+</body>
diff --git a/dom/tests/mochitest/localstorage/frameKeySync.html b/dom/tests/mochitest/localstorage/frameKeySync.html
new file mode 100644
index 0000000000..a6b39d47d7
--- /dev/null
+++ b/dom/tests/mochitest/localstorage/frameKeySync.html
@@ -0,0 +1,51 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<title>frame for localStorage test</title>
+
+<script type="text/javascript" src="interOriginFrame.js"></script>
+<script type="text/javascript">
+
+var currentStep = parseInt(location.search.substring(1));
+
+function doStep()
+{
+ switch (currentStep)
+ {
+ case 1:
+ localStorage.clear();
+ break;
+
+ case 2:
+ localStorage.setItem("a", "1");
+ is(localStorage.a, "1", "Value a=1 set");
+ break;
+
+ case 3:
+ try {
+ is(localStorage.key(0), "a", "Key 'a' present in 'key' array")
+ }
+ catch (exc) {
+ ok(false, "Shouldn't throw when accessing key(0) " + exc);
+ }
+ is(localStorage.a, "1", "Value a=1 set");
+ break;
+
+ default:
+ return finishTest();
+ }
+
+ // Increase by two to as odd number are executed in a window separate from
+ // where even step are.
+ ++currentStep;
+ ++currentStep;
+
+ return true;
+}
+
+</script>
+
+</head>
+
+<body onload="postMsg('frame loaded');">
+</body>
+</html>
diff --git a/dom/tests/mochitest/localstorage/frameLocalStorageCookieSettings.html b/dom/tests/mochitest/localstorage/frameLocalStorageCookieSettings.html
new file mode 100644
index 0000000000..4952a81c44
--- /dev/null
+++ b/dom/tests/mochitest/localstorage/frameLocalStorageCookieSettings.html
@@ -0,0 +1,26 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<title>localStorage cookies settings test</title>
+
+</head>
+<body>
+<script type="text/javascript">
+ function ok(what, msg) {
+ parent.postMessage({ type: "ok", what: !!what, msg }, "*");
+ }
+
+ function is(a, b, msg) {
+ ok(a === b, msg);
+ }
+
+ try {
+ localStorage.setItem("contentkey", "test-value");
+ ok(false, "Setting localStorageItem should throw a security exception");
+ } catch(ex) {
+ is(ex.name, "SecurityError", "Got security exception");
+ }
+
+ parent.postMessage({ type: "finish" }, "*");
+</script>
+</body>
+</html>
diff --git a/dom/tests/mochitest/localstorage/frameLocalStorageSessionOnly.html b/dom/tests/mochitest/localstorage/frameLocalStorageSessionOnly.html
new file mode 100644
index 0000000000..f6c7f0291f
--- /dev/null
+++ b/dom/tests/mochitest/localstorage/frameLocalStorageSessionOnly.html
@@ -0,0 +1,8 @@
+<!doctype html>
+<html>
+ <body>
+ <script>
+ parent.postMessage(SpecialPowers.wrap(localStorage).isSessionOnly, "*");
+ </script>
+ </body>
+</html>
diff --git a/dom/tests/mochitest/localstorage/frameMasterEqual.html b/dom/tests/mochitest/localstorage/frameMasterEqual.html
new file mode 100644
index 0000000000..4d83c4fef2
--- /dev/null
+++ b/dom/tests/mochitest/localstorage/frameMasterEqual.html
@@ -0,0 +1,56 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<title>frame for localStorage test</title>
+
+<script type="text/javascript" src="interOriginFrame.js"></script>
+<script type="text/javascript">
+
+var currentStep = 1;
+
+function doStep()
+{
+ switch (currentStep)
+ {
+ case 1:
+ localStorage.setItem("X", "1");
+ is(localStorage.getItem("X"), "1", "X is 1 in the master");
+ break;
+
+ case 3:
+ is(localStorage.getItem("X"), "2", "X set to 2 in the master");
+ localStorage.removeItem("X");
+ is(localStorage.getItem("X"), null, "X was removed from the master");
+ break;
+
+ case 5:
+ is(localStorage.getItem("Y"), "3", "Y is 3 in the master");
+ localStorage.setItem("Z", "4");
+ is(localStorage.getItem("Z"), "4", "Z is 4 in the master");
+
+ localStorage.clear();
+ is(localStorage.length, 0, "Master is empty");
+ break;
+
+ case 7:
+ is(localStorage.length, 0, "Master is empty");
+ break;
+
+ case 9:
+ return finishTest();
+ }
+
+ // Increase by two to distinguish each test step order
+ // in both master doStep and slave doStep functions.
+ ++currentStep;
+ ++currentStep;
+
+ return true;
+}
+
+</script>
+
+</head>
+
+<body onload="postMsg('frame loaded');">
+</body>
+</html>
diff --git a/dom/tests/mochitest/localstorage/frameMasterNotEqual.html b/dom/tests/mochitest/localstorage/frameMasterNotEqual.html
new file mode 100644
index 0000000000..fef476bed3
--- /dev/null
+++ b/dom/tests/mochitest/localstorage/frameMasterNotEqual.html
@@ -0,0 +1,47 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<title>frame for localStorage test</title>
+
+<script type="text/javascript" src="interOriginFrame.js"></script>
+<script type="text/javascript">
+
+var currentStep = 1;
+
+function doStep()
+{
+ switch (currentStep)
+ {
+ case 1:
+ localStorage.setItem("X", "1");
+ is(localStorage.getItem("X"), "1", "X is 1 in the master");
+ break;
+
+ case 3:
+ is(localStorage.getItem("X"), "1", "X remains 1 in the master");
+ localStorage.removeItem("X");
+ is(localStorage.getItem("X"), null, "X was removed from the master");
+ break;
+
+ case 5:
+ is(localStorage.getItem("Y"), null, "Y null in the master");
+ break;
+
+ case 7:
+ return finishTest();
+ }
+
+ // Increase by two to distinguish each test step order
+ // in both master doStep and slave doStep functions.
+ ++currentStep;
+ ++currentStep;
+
+ return true;
+}
+
+</script>
+
+</head>
+
+<body onload="postMsg('frame loaded');">
+</body>
+</html>
diff --git a/dom/tests/mochitest/localstorage/frameOrder.html b/dom/tests/mochitest/localstorage/frameOrder.html
new file mode 100644
index 0000000000..3b3f0ebef8
--- /dev/null
+++ b/dom/tests/mochitest/localstorage/frameOrder.html
@@ -0,0 +1,27 @@
+<html>
+<head>
+</head>
+<script type="text/javascript">
+function doTest()
+{
+ var query = location.search.substring(1);
+ query = unescape(query);
+ var keyNames = eval(query);
+
+ parent.is(localStorage.a, "10", "a = 10");
+ parent.is(localStorage.b, "20", "b = 20");
+ parent.is(localStorage.c, "30", "c = 30");
+ parent.is(localStorage.d, "40", "d = 40");
+ parent.is(localStorage.e, "50", "e = 50");
+ parent.is(localStorage.length, 5, "length = 5");
+
+ for (var i = 0; i < localStorage.length; ++i)
+ parent.is(keyNames[i], localStorage.key(i), "key "+keyNames[i]+" on same index");
+
+ parent.SimpleTest.finish();
+ localStorage.clear();
+}
+</script>
+<body onload="doTest();">
+</body>
+</html>
diff --git a/dom/tests/mochitest/localstorage/frameQuota.html b/dom/tests/mochitest/localstorage/frameQuota.html
new file mode 100644
index 0000000000..5ff9855c99
--- /dev/null
+++ b/dom/tests/mochitest/localstorage/frameQuota.html
@@ -0,0 +1,97 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<title>slave for sessionStorage test</title>
+
+<script type="text/javascript" src="interOriginFrame.js"></script>
+<script type="text/javascript">
+
+const DOM_QUOTA_EXCEEDED_ERR = 0x80530016;
+
+function checkException(func, exc)
+{
+ var exceptionThrew = false;
+ try {
+ func();
+ }
+ catch (ex) {
+ exceptionThrew = true;
+ is(ex.result, exc, "Expected "+exc+" exception");
+ }
+ ok(exceptionThrew, "Exception "+exc+" threw at "+location);
+}
+
+function doStep()
+{
+ var query = location.search.substring(1);
+ var queries = query.split("&");
+
+ var operation = queries[0];
+ var keyName = queries[1];
+ var result = queries[2];
+
+ switch (result)
+ {
+ case "success":
+ switch (operation)
+ {
+ case "add":
+ // Store 500 bytes long string must succeed
+ localStorage.setItem(keyName, "12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890");
+ is(localStorage.getItem(keyName), "12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890", "500 bytes key "+keyName+" stored");
+ break;
+
+ case "remove":
+ localStorage.removeItem(keyName);
+ is(localStorage.getItem(keyName), null, "Key "+keyName+" removed");
+ break;
+ }
+
+ break;
+
+ case "failure":
+ switch (operation)
+ {
+ case "add":
+ // Attempt to store 500 bytes long string that doens't
+ // fit the quota, have to throw DOM_QUOTA_EXCEEDED_ERR exception
+ checkException(function() {
+ localStorage.setItem(keyName, "12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890");
+ }, DOM_QUOTA_EXCEEDED_ERR);
+ is(localStorage.getItem(keyName), null, "500 bytes key "+keyName+" is NOT stored");
+ break;
+
+ case "add2":
+ // Attempt to change a key value to reach the DOM quota and
+ // check it fails and the old key value is still present.
+ checkException(function() {
+ localStorage.setItem(keyName, "123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890");
+ }, DOM_QUOTA_EXCEEDED_ERR);
+ is(localStorage.getItem(keyName), "12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890", "Key "+keyName+" left unchanged");
+ break;
+ }
+
+ break;
+
+ default:
+ switch (operation)
+ {
+ case "clear":
+ localStorage.clear();
+ break;
+ }
+
+ break;
+ }
+
+ // Just inform the master we are finished now
+ postMsg("done");
+ return false;
+}
+
+</script>
+
+</head>
+
+<body onload="postMsg('frame loaded');">
+</body>
+</html>
diff --git a/dom/tests/mochitest/localstorage/frameQuotaSessionOnly.html b/dom/tests/mochitest/localstorage/frameQuotaSessionOnly.html
new file mode 100644
index 0000000000..754a5b3598
--- /dev/null
+++ b/dom/tests/mochitest/localstorage/frameQuotaSessionOnly.html
@@ -0,0 +1,101 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<title>slave for sessionStorage test</title>
+
+<script type="text/javascript" src="interOriginFrame.js"></script>
+<script type="text/javascript">
+
+const DOM_QUOTA_EXCEEDED_ERR = 0x80530016;
+
+function checkException(func, exc)
+{
+ var exceptionThrew = false;
+ try {
+ func();
+ }
+ catch (ex) {
+ exceptionThrew = true;
+ is(ex.result, exc, "Expected "+exc+" exception");
+ }
+ ok(exceptionThrew, "Exception "+exc+" threw at "+location);
+}
+
+function doStep()
+{
+ var query = location.search.substring(1);
+ var queries = query.split("&");
+
+ var operation = queries[0];
+ var keyName = queries[1];
+ var result = queries[2];
+
+ switch (result)
+ {
+ case "success":
+ switch (operation)
+ {
+ case "add":
+ // Store 500 bytes long string must succeed
+ localStorage.setItem(keyName, "12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890");
+ is(localStorage.getItem(keyName), "12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890", "500 bytes key "+keyName+" stored");
+ break;
+
+ case "remove":
+ localStorage.removeItem(keyName);
+ is(localStorage.getItem(keyName), null, "Key "+keyName+" removed");
+ break;
+ }
+
+ break;
+
+ case "failure":
+ switch (operation)
+ {
+ case "add":
+ // Attempt to store 500 bytes long string that doens't
+ // fit the quota, have to throw DOM_QUOTA_EXCEEDED_ERR exception
+ checkException(function() {
+ localStorage.setItem(keyName, "12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890");
+ }, DOM_QUOTA_EXCEEDED_ERR);
+ is(localStorage.getItem(keyName), null, "500 bytes key "+keyName+" is NOT stored");
+ break;
+
+ case "add2":
+ // Attempt to change a key value to reach the DOM quota and
+ // check it fails and the old key value is still present.
+ checkException(function() {
+ localStorage.setItem(keyName, "123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890");
+ }, DOM_QUOTA_EXCEEDED_ERR);
+ is(localStorage.getItem(keyName), "12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890", "Key "+keyName+" left unchanged");
+ break;
+ }
+
+ break;
+
+ case "":
+ default:
+ switch (operation)
+ {
+ case "clear":
+ localStorage.clear();
+ break;
+ }
+
+ break;
+ }
+
+ // Just inform the master we are finished now
+ postMsg("done");
+ return false;
+}
+
+function startTest() {
+ postMsg('frame loaded');
+}
+</script>
+
+</head>
+
+<body onload="startTest();">
+</body>
+</html>
diff --git a/dom/tests/mochitest/localstorage/frameReplace.html b/dom/tests/mochitest/localstorage/frameReplace.html
new file mode 100644
index 0000000000..145bfe8fce
--- /dev/null
+++ b/dom/tests/mochitest/localstorage/frameReplace.html
@@ -0,0 +1,72 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<title>localStorage replace frame</title>
+
+<script type="text/javascript">
+
+var shell;
+
+function ok(a, message)
+{
+ if (!a)
+ shell.postMessage("FAILURE: " + message, "http://mochi.test:8888");
+ else
+ shell.postMessage(message, "http://mochi.test:8888");
+}
+
+function is(a, b, message)
+{
+ if (a != b)
+ shell.postMessage("FAILURE: " + message + ", expected "+b+" got "+a, "http://mochi.test:8888");
+ else
+ shell.postMessage(message + ", expected "+b+" got "+a, "http://mochi.test:8888");
+}
+
+function doTest()
+{
+ var query = location.search.substring(1);
+ var queries = query.split("&");
+
+ var action = queries[0];
+ shell = queries[1];
+ switch (shell)
+ {
+ case "frame":
+ shell = parent;
+ break;
+ case "window":
+ shell = opener;
+ break;
+ }
+
+ switch (action)
+ {
+ case "init":
+ localStorage.setItem("A", "1");
+ localStorage.setItem("B", "2");
+ localStorage.setItem("C", "3");
+ is(localStorage.getItem("A"), "1", "'A' is '1'");
+ is(localStorage.getItem("B"), "2", "'A' is '2'");
+ is(localStorage.getItem("C"), "3", "'A' is '3'");
+ break;
+
+ case "check":
+ is(localStorage.getItem("A"), null, "'A' is null");
+ is(localStorage.getItem("B"), null, "'A' is null");
+ is(localStorage.getItem("C"), null, "'A' is null");
+ break;
+
+ case "clean":
+ localStorage.clear();
+ break;
+ }
+
+ shell.postMessage(action + "_done", "http://mochi.test:8888");
+}
+
+</script>
+
+</head>
+<body onload="doTest();">
+</body>
+</html>
diff --git a/dom/tests/mochitest/localstorage/frameSlaveEqual.html b/dom/tests/mochitest/localstorage/frameSlaveEqual.html
new file mode 100644
index 0000000000..b64b8de10a
--- /dev/null
+++ b/dom/tests/mochitest/localstorage/frameSlaveEqual.html
@@ -0,0 +1,51 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<title>frame for localStorage test</title>
+
+<script type="text/javascript" src="interOriginFrame.js"></script>
+<script type="text/javascript">
+
+var currentStep = 2;
+
+function doStep()
+{
+ switch (currentStep)
+ {
+ case 2:
+ is(localStorage.getItem("X"), "1", "X is 1 in the slave");
+ localStorage.setItem("X", "2");
+ is(localStorage.getItem("X"), "2", "X set to 2 in the slave");
+ break;
+
+ case 4:
+ is(localStorage.getItem("X"), null, "X was removed from the slave");
+ localStorage.setItem("Y", "3");
+ is(localStorage.getItem("Y"), "3", "Y set to 3 in the slave");
+ break;
+
+ case 6:
+ is(localStorage.length, 0, "Slave is empty");
+ is(localStorage.getItem("X"), null, "X is null in the slave");
+ is(localStorage.getItem("Y"), null, "Y is null in the slave");
+ is(localStorage.getItem("Z"), null, "Z is null in the slave");
+ break;
+
+ case 8:
+ return finishTest();
+ }
+
+ // Increase by two to distinguish each test step order
+ // in both master doStep and slave doStep functions.
+ ++currentStep;
+ ++currentStep;
+
+ return true;
+}
+
+</script>
+
+</head>
+
+<body onload="postMsg('frame loaded');">
+</body>
+</html>
diff --git a/dom/tests/mochitest/localstorage/frameSlaveNotEqual.html b/dom/tests/mochitest/localstorage/frameSlaveNotEqual.html
new file mode 100644
index 0000000000..9daf9e9f73
--- /dev/null
+++ b/dom/tests/mochitest/localstorage/frameSlaveNotEqual.html
@@ -0,0 +1,44 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<title>frame for localStorage test</title>
+
+<script type="text/javascript" src="interOriginFrame.js"></script>
+<script type="text/javascript">
+
+var currentStep = 2;
+
+function doStep()
+{
+ switch (currentStep)
+ {
+ case 2:
+ is(localStorage.getItem("X"), null, "X not set in the slave");
+ localStorage.setItem("X", "2");
+ is(localStorage.getItem("X"), "2", "X set to 2 in the slave");
+ break;
+
+ case 4:
+ is(localStorage.getItem("X"), "2", "X still set to 2 in the slave");
+ localStorage.setItem("Y", "3");
+ is(localStorage.getItem("Y"), "3", "Y set to 4 (MUST FAIL!) in the slave");
+ break;
+
+ case 6:
+ return finishTest();
+ }
+
+ // Increase by two to distinguish each test step order
+ // in both master doStep and slave doStep functions.
+ ++currentStep;
+ ++currentStep;
+
+ return true;
+}
+
+</script>
+
+</head>
+
+<body onload="postMsg('frame loaded');">
+</body>
+</html>
diff --git a/dom/tests/mochitest/localstorage/interOriginFrame.js b/dom/tests/mochitest/localstorage/interOriginFrame.js
new file mode 100644
index 0000000000..64470c4ef6
--- /dev/null
+++ b/dom/tests/mochitest/localstorage/interOriginFrame.js
@@ -0,0 +1,53 @@
+function postMsg(message) {
+ parent.postMessage(message, "http://mochi.test:8888");
+}
+
+window.addEventListener("message", onMessageReceived);
+
+function onMessageReceived(event) {
+ if (event.data == "step") {
+ var performed = false;
+ try {
+ performed = doStep();
+ } catch (ex) {
+ postMsg("FAILURE: exception threw at " + location + ":\n" + ex);
+ finishTest();
+ }
+
+ if (performed) {
+ postMsg("perf");
+ }
+
+ return;
+ }
+
+ postMsg("Invalid message");
+}
+
+function ok(a, message) {
+ if (!a) {
+ postMsg("FAILURE: " + message);
+ } else {
+ postMsg(message);
+ }
+}
+
+function is(a, b, message) {
+ if (a != b) {
+ postMsg("FAILURE: " + message + ", expected " + b + " got " + a);
+ } else {
+ postMsg(message + ", expected " + b + " got " + a);
+ }
+}
+
+function todo(a, b, message) {
+ postMsg("TODO: " + message + ", expected " + b + " got " + a);
+}
+
+function finishTest() {
+ try {
+ localStorage.clear();
+ } catch (e) {}
+ postMsg("done");
+ return false;
+}
diff --git a/dom/tests/mochitest/localstorage/interOriginTest.js b/dom/tests/mochitest/localstorage/interOriginTest.js
new file mode 100644
index 0000000000..526b5b0fb1
--- /dev/null
+++ b/dom/tests/mochitest/localstorage/interOriginTest.js
@@ -0,0 +1,41 @@
+var slaveLoadsPending = 1;
+
+var slaveOrigin = "";
+var slave = null;
+
+var failureRegExp = new RegExp("^FAILURE");
+const slavePath = "/tests/dom/tests/mochitest/localstorage/";
+
+window.addEventListener("message", onMessageReceived);
+
+function onMessageReceived(event) {
+ switch (event.data) {
+ // Indication of the frame onload event
+ case "frame loaded":
+ if (--slaveLoadsPending) {
+ break;
+ }
+
+ // Indication of successfully finished step of a test
+ // fall through
+ case "perf":
+ if (event.data == "perf") {
+ doStep();
+ }
+
+ slave.postMessage("step", slaveOrigin);
+ break;
+
+ // Indication of all test parts finish (from any of the frames)
+ case "done":
+ localStorage.clear();
+ slaveLoadsPending = 1;
+ doNextTest();
+ break;
+
+ // Any other message indicates error or succes message of a test
+ default:
+ SimpleTest.ok(!event.data.match(failureRegExp), event.data);
+ break;
+ }
+}
diff --git a/dom/tests/mochitest/localstorage/interOriginTest2.js b/dom/tests/mochitest/localstorage/interOriginTest2.js
new file mode 100644
index 0000000000..d675475c76
--- /dev/null
+++ b/dom/tests/mochitest/localstorage/interOriginTest2.js
@@ -0,0 +1,53 @@
+var t = async_test(document.title);
+
+var frameLoadsPending = 2;
+
+var callMasterFrame = true;
+var testDone = false;
+
+var masterFrameOrigin = "";
+var slaveFrameOrigin = "";
+
+var failureRegExp = new RegExp("^FAILURE");
+
+const framePath = "/tests/dom/tests/mochitest/localstorage/";
+
+window.addEventListener("message", onMessageReceived);
+
+function onMessageReceived(event) {
+ switch (event.data) {
+ // Indication of the frame onload event
+ case "frame loaded":
+ if (--frameLoadsPending) {
+ break;
+ }
+
+ // Indication of successfully finished step of a test
+ // Just fall through...
+ case "perf":
+ if (callMasterFrame) {
+ masterFrame.postMessage("step", masterFrameOrigin);
+ } else {
+ slaveFrame.postMessage("step", slaveFrameOrigin);
+ }
+ callMasterFrame = !callMasterFrame;
+ break;
+
+ // Indication of all test parts finish (from any of the frames)
+ case "done":
+ if (testDone) {
+ break;
+ }
+
+ testDone = true;
+ t.done();
+ break;
+
+ // Any other message indicates error, succes or todo message of a test
+ default:
+ t.step(function () {
+ assert_true(!event.data.match(failureRegExp), event.data);
+ });
+ break;
+ }
+}
diff --git a/dom/tests/mochitest/localstorage/localStorageCommon.js b/dom/tests/mochitest/localstorage/localStorageCommon.js
new file mode 100644
index 0000000000..364e708870
--- /dev/null
+++ b/dom/tests/mochitest/localstorage/localStorageCommon.js
@@ -0,0 +1,131 @@
+function localStorageFlush(cb) {
+ if (SpecialPowers.Services.domStorageManager.nextGenLocalStorageEnabled) {
+ SimpleTest.executeSoon(function () {
+ cb();
+ });
+ return;
+ }
+
+ var ob = {
+ observe(sub, top, dat) {
+ os().removeObserver(ob, "domstorage-test-flushed");
+ cb();
+ },
+ };
+ os().addObserver(ob, "domstorage-test-flushed");
+ notify("domstorage-test-flush-force");
+}
+
+function localStorageReload(callback) {
+ if (SpecialPowers.Services.domStorageManager.nextGenLocalStorageEnabled) {
+ localStorage.close();
+ let qms = SpecialPowers.Services.qms;
+ let principal = SpecialPowers.wrap(document).nodePrincipal;
+ let request = qms.resetStoragesForPrincipal(principal, "default", "ls");
+ request.callback = SpecialPowers.wrapCallback(function () {
+ localStorage.open();
+ callback();
+ });
+ return;
+ }
+
+ notify("domstorage-test-reload");
+ SimpleTest.executeSoon(function () {
+ callback();
+ });
+}
+
+function localStorageFlushAndReload(callback) {
+ if (SpecialPowers.Services.domStorageManager.nextGenLocalStorageEnabled) {
+ localStorage.close();
+ let qms = SpecialPowers.Services.qms;
+ let principal = SpecialPowers.wrap(document).nodePrincipal;
+ let request = qms.resetStoragesForPrincipal(principal, "default", "ls");
+ request.callback = SpecialPowers.wrapCallback(function () {
+ localStorage.open();
+ callback();
+ });
+ return;
+ }
+
+ localStorageFlush(function () {
+ localStorageReload(callback);
+ });
+}
+
+function localStorageClearAll(callback) {
+ if (SpecialPowers.Services.domStorageManager.nextGenLocalStorageEnabled) {
+ let qms = SpecialPowers.Services.qms;
+ let ssm = SpecialPowers.Services.scriptSecurityManager;
+
+ qms.getUsage(
+ SpecialPowers.wrapCallback(function (request) {
+ if (request.resultCode != SpecialPowers.Cr.NS_OK) {
+ callback();
+ return;
+ }
+
+ let clearRequestCount = 0;
+ for (let item of request.result) {
+ let principal = ssm.createContentPrincipalFromOrigin(item.origin);
+ let clearRequest = qms.clearStoragesForPrincipal(
+ principal,
+ "default",
+ "ls"
+ );
+ clearRequestCount++;
+ clearRequest.callback = SpecialPowers.wrapCallback(function () {
+ if (--clearRequestCount == 0) {
+ callback();
+ }
+ });
+ }
+ })
+ );
+ return;
+ }
+
+ os().notifyObservers(null, "cookie-changed", "cleared");
+ SimpleTest.executeSoon(function () {
+ callback();
+ });
+}
+
+function localStorageClearDomain(domain, callback) {
+ if (SpecialPowers.Services.domStorageManager.nextGenLocalStorageEnabled) {
+ let qms = SpecialPowers.Services.qms;
+ let principal = SpecialPowers.wrap(document).effectiveStoragePrincipal;
+ let request = qms.clearStoragesForPrincipal(principal, "default", "ls");
+ let cb = SpecialPowers.wrapCallback(callback);
+ request.callback = cb;
+ return;
+ }
+
+ os().notifyObservers(null, "extension:purge-localStorage", domain);
+ SimpleTest.executeSoon(function () {
+ callback();
+ });
+}
+
+function os() {
+ return SpecialPowers.Services.obs;
+}
+
+function notify(top) {
+ os().notifyObservers(null, top);
+}
+
+/**
+ * Enable testing observer notifications in DOMStorageObserver.cpp.
+ */
+function localStorageEnableTestingMode(cb) {
+ SpecialPowers.pushPrefEnv(
+ {
+ set: [
+ ["dom.storage.testing", true],
+ ["dom.quotaManager.testing", true],
+ ],
+ },
+ cb
+ );
+}
diff --git a/dom/tests/mochitest/localstorage/mochitest.ini b/dom/tests/mochitest/localstorage/mochitest.ini
new file mode 100644
index 0000000000..de5eb88304
--- /dev/null
+++ b/dom/tests/mochitest/localstorage/mochitest.ini
@@ -0,0 +1,63 @@
+[DEFAULT]
+support-files =
+ frameChromeSlave.html
+ frameLocalStorageCookieSettings.html
+ frameKeySync.html
+ frameMasterEqual.html
+ frameMasterNotEqual.html
+ frameOrder.html
+ frameQuota.html
+ frameQuotaSessionOnly.html
+ frameReplace.html
+ frameSlaveEqual.html
+ frameSlaveNotEqual.html
+ interOriginFrame.js
+ interOriginTest.js
+ interOriginTest2.js
+ localStorageCommon.js
+ frameLocalStorageSessionOnly.html
+ file_tryAccessSessionStorage.html
+ windowProxy.html
+
+[test_brokenUTF-16.html]
+[test_bug600307-DBOps.html]
+[test_bug746272-1.html]
+[test_bug746272-2.html]
+skip-if = verify
+[test_cookieBlock.html]
+[test_embededNulls.html]
+[test_keySync.html]
+skip-if =
+ http3
+[test_localStorageBase.html]
+[test_localStorageBaseSessionOnly.html]
+[test_localStorageCookieSettings.html]
+[test_localStorageEnablePref.html]
+[test_localStorageKeyOrder.html]
+skip-if =
+ http3
+[test_localStorageOriginsDiff.html]
+skip-if =
+ http3
+[test_localStorageOriginsDomainDiffs.html]
+skip-if =
+ http3
+[test_localStorageOriginsEquals.html]
+skip-if =
+ http3
+[test_localStorageOriginsPortDiffs.html]
+skip-if =
+ http3
+[test_localStorageOriginsSchemaDiffs.html]
+skip-if =
+ http3
+[test_localStorageQuota.html]
+skip-if =
+ http3
+[test_localStorageQuotaSessionOnly.html]
+[test_localStorageQuotaSessionOnly2.html]
+skip-if = true # bug 1347690
+[test_localStorageReplace.html]
+skip-if =
+ http3
+[test_storageConstructor.html]
diff --git a/dom/tests/mochitest/localstorage/page_blank.html b/dom/tests/mochitest/localstorage/page_blank.html
new file mode 100644
index 0000000000..157317d64b
--- /dev/null
+++ b/dom/tests/mochitest/localstorage/page_blank.html
@@ -0,0 +1,6 @@
+<!DOCTYPE html>
+<html>
+<body>
+
+</body>
+</html>
diff --git a/dom/tests/mochitest/localstorage/test_brokenUTF-16.html b/dom/tests/mochitest/localstorage/test_brokenUTF-16.html
new file mode 100644
index 0000000000..a9289b195c
--- /dev/null
+++ b/dom/tests/mochitest/localstorage/test_brokenUTF-16.html
@@ -0,0 +1,100 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<title>incomplete UTF-16 test</title>
+<meta http-equiv="Content-type" content="text/html; charset=UTF-8" />
+
+<script src="/tests/SimpleTest/SimpleTest.js"></script>
+<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+
+<script type="text/javascript">
+
+function startTest()
+{
+ // Check this works for a diacritics
+ var k = "valid UTF-16 key";
+ var v = "ěščřžýáíéúůĚŠČŘŽÝÁÍÉÚŮ";
+
+ localStorage.setItem(k, v);
+ is(localStorage.getItem(k), v, "UTF-16 value results from getItem");
+
+ localStorage.setItem(v, "a value");
+ is(localStorage.getItem(v), "a value", "value result using UTF-16 key from getItem");
+
+ localStorage.clear();
+
+ localStorage[k] = v;
+ is(localStorage[k], v, "UTF-16 value results from []");
+
+ localStorage[v] = "a value";
+ is(localStorage[v], "a value", "value result using UTF-16 key from []");
+
+ localStorage.clear();
+
+ localStorage.aKey = v;
+ is(localStorage.aKey, v, "UTF-16 value results from a dynamic property");
+
+ localStorage.clear();
+
+ // Broken UTF-16
+ k = "broken UTF-16 key";
+ v = "\uD800"; // broken UTF-16
+
+ localStorage.setItem(k, v);
+ is(localStorage.getItem(k), v, "broken value results from getItem");
+
+ localStorage.setItem(v, "a value");
+ is(localStorage.getItem(v), "a value", "value result using broken key from getItem");
+
+ localStorage.clear();
+
+ localStorage[k] = v;
+ is(localStorage[k], v, "broken value results from []");
+
+ localStorage[v] = "a value";
+ is(localStorage[v], "a value", "value result using broken key from []");
+
+ localStorage.clear();
+
+ localStorage.aKey = v;
+ is(localStorage.aKey, v, "broken value results from a dynamic property");
+
+ localStorage.clear();
+
+ // Another variant
+ v = "FcK"
+ + String.fromCharCode(0x8a)
+ + ".jp";
+
+ localStorage.setItem(k, v);
+ is(localStorage.getItem(k), v);
+
+ localStorage.setItem(v, "a value");
+ is(localStorage.getItem(v), "a value");
+
+ localStorage.clear();
+
+ // And yet another variant
+ v = "something"
+ + String.fromCharCode(355, 277, 349, 357, 533, 537, 101, 345);
+
+ localStorage.setItem(k, v);
+ is(localStorage.getItem(k), v);
+
+ localStorage.setItem(v, "a value");
+ is(localStorage.getItem(v), "a value");
+
+ localStorage.clear();
+
+ SimpleTest.finish();
+}
+
+SimpleTest.waitForExplicitFinish();
+
+</script>
+
+</head>
+
+<body onload="startTest();">
+
+</body>
+</html>
diff --git a/dom/tests/mochitest/localstorage/test_bug600307-DBOps.html b/dom/tests/mochitest/localstorage/test_bug600307-DBOps.html
new file mode 100644
index 0000000000..cfce270d5d
--- /dev/null
+++ b/dom/tests/mochitest/localstorage/test_bug600307-DBOps.html
@@ -0,0 +1,178 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<title>bug 600307</title>
+
+<script src="/tests/SimpleTest/SimpleTest.js"></script>
+<script type="text/javascript" src="localStorageCommon.js"></script>
+<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+
+<script type="text/javascript">
+
+/* eslint-disable max-nested-callbacks */
+
+/*
+This is strictly implementation specific test for dom storage code from bug 600307.
+It exercises code for asynchronous data flushing with regard to cache life time and its preload.
+
+"flush + reload" means to tell the database to store all pending data then wipe the cached content and reload it from the db
+
+"reload" only means to simulate situation when there is a pending flush for an origin but a new cache is about to preload
+which is a corner case happening rarely ; this helps check the next preload operation will load correct data from the database anyway
+
+Case 1: set | flush + reload | remove | set | remove | flush + reload | get ?= null
+ checks coalescing optimization for single key changes does work correctly for repeated removals of a key
+
+Case 2: set | set | clear | flush + reload | count ?= 0
+ checks whether clear operation superseeds setting keys, the database must be empty for the origin
+
+Case 3: set | set | clear | reload | count ?= 0
+ check the corner case when a data clear flush is pending but a new cache is about to preload
+*/
+
+function startTest()
+{
+ // Enable testing observer notifications
+ localStorageEnableTestingMode(function() {
+
+ // Have an untouched land
+ localStorage.clear();
+
+ // Initial flush
+ localStorageFlush(function() {
+ is(localStorage.length, 0, "localStorage empty at the test start");
+
+ // Basic test 1 (set a key, check presence after reload):
+ localStorage.setItem("item", "value");
+ localStorageFlushAndReload(function() {
+ is(localStorage.getItem("item"), "value", "Basic persistance works");
+ is(localStorage.length, 1, "1 item in localStorage");
+
+ // Basic test 2 (set a key twice, check presence of the last value):
+ localStorage.setItem("item", "value2");
+ localStorage.setItem("item", "value3");
+ localStorageFlushAndReload(function() {
+ is(localStorage.getItem("item"), "value3", "Basic persistance 2 works");
+
+ // Basic test 3 (remove a key, check it has been deleted):
+ localStorage.removeItem("item");
+ localStorageFlushAndReload(function() {
+ is(localStorage.getItem("item"), null, "Basic delete works");
+
+ // Basic test 4 (set and remove a key, check it is not present):
+ localStorage.setItem("item", "value4");
+ localStorage.removeItem("item");
+ localStorageFlushAndReload(function() {
+ is(localStorage.getItem("item"), null, "Basic delete 2 works");
+
+
+ // Case 1:
+ localStorage.setItem("item", "value");
+ localStorageFlushAndReload(function() {
+ localStorage.removeItem("item");
+ localStorage.setItem("item", "value2");
+ localStorage.removeItem("item");
+ localStorageFlushAndReload(function() {
+ is(localStorage.getItem("item"), null, "Item deleted in case 1");
+
+ // Case 2:
+ localStorage.setItem("item", "value");
+ localStorage.setItem("item2", "value2");
+ localStorage.clear();
+ localStorageFlushAndReload(function() {
+ is(localStorage.length, 0, "localStorage clean in case 2");
+
+ // Case 3:
+ localStorageFlush(function() {
+ localStorage.setItem("item", "value");
+ localStorage.setItem("item2", "value2");
+ localStorage.clear();
+ localStorageReload(function() {
+ is(localStorage.length, 0, "localStorage clean in case 4");
+
+ if (!SpecialPowers.Services.domStorageManager.nextGenLocalStorageEnabled &&
+ SpecialPowers.Cc["@mozilla.org/xre/app-info;1"].getService(
+ SpecialPowers.Ci.nsIXULRuntime).processType != SpecialPowers.Ci.nsIXULRuntime.PROCESS_TYPE_DEFAULT) {
+ // Following tests cannot be run in a child/plugin process type
+ SimpleTest.finish();
+ return;
+ }
+
+ // Cookies clean 1
+ localStorageFlush(function() {
+ localStorage.setItem("item", "value");
+ localStorageClearAll(function() {
+ is(localStorage.length, 0, "localStorage clean after cookies deletion");
+ localStorage.setItem("item2", "value2");
+ is(localStorage.getItem("item"), null, "Unexpected key 1, cookies delete");
+ is(localStorage.getItem("item2"), "value2", "Expected key 2, cookies delete");
+ localStorageFlushAndReload(function() {
+ is(localStorage.getItem("item"), null, "Unexpected key 1, cookies delete");
+ is(localStorage.getItem("item2"), "value2", "Expected key 2, cookies delete");
+
+ // Cookies clean 2
+ localStorage.clear();
+ localStorageFlush(function() {
+ localStorage.setItem("item", "value");
+ localStorageClearAll(function() {
+ is(localStorage.length, 0, "localStorage clean after cookies deletion 2");
+ localStorageFlushAndReload(function() {
+ is(localStorage.length, 0, "localStorage clean after cookies deletion 2");
+
+
+ // Domain clean 1
+ localStorageFlush(function() {
+ localStorage.setItem("item", "value");
+ localStorageClearDomain("test", function() {
+ is(localStorage.length, 0, "localStorage clean after domain deletion");
+ localStorage.setItem("item2", "value2");
+ is(localStorage.getItem("item"), null, "Unexpected key 1, domain delete");
+ is(localStorage.getItem("item2"), "value2", "Expected key 2, domain delete");
+ localStorageFlushAndReload(function() {
+ is(localStorage.getItem("item"), null, "Unexpected key 1, domain delete");
+ is(localStorage.getItem("item2"), "value2", "Expected key 2, domain delete");
+
+ // Domain clean 2
+ localStorage.clear();
+ localStorageFlush(function() {
+ localStorage.setItem("item", "value");
+ localStorageClearDomain("test", function() {
+ is(localStorage.length, 0, "localStorage clean after domain deletion 2");
+ localStorageFlushAndReload(function() {
+ is(localStorage.length, 0, "localStorage clean after domain deletion 2");
+
+ SimpleTest.finish();
+
+ });
+ });
+ });
+ });
+ });
+ });
+ });
+ });
+ });
+ });
+ });
+ });
+ });
+ });
+ });
+ });
+ });
+ });
+ });
+ });
+ });
+ });
+ });
+}
+
+SimpleTest.waitForExplicitFinish();
+
+</script>
+
+</head>
+
+<body onload="startTest();">
+</body>
+</html>
diff --git a/dom/tests/mochitest/localstorage/test_bug746272-1.html b/dom/tests/mochitest/localstorage/test_bug746272-1.html
new file mode 100644
index 0000000000..36612fe79f
--- /dev/null
+++ b/dom/tests/mochitest/localstorage/test_bug746272-1.html
@@ -0,0 +1,32 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<title>incomplete UTF-16 test</title>
+<meta http-equiv="Content-type" content="text/html; charset=UTF-8" />
+
+<script src="/tests/SimpleTest/SimpleTest.js"></script>
+<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+
+<script type="text/javascript">
+
+function startTest()
+{
+ localStorage.clear();
+ localStorage.setItem("test1", "value1");
+ localStorage.setItem("test2", "value2");
+ localStorage.setItem("test3", "value3");
+
+ is(localStorage.length, 3, "expected number of items");
+
+ SimpleTest.finish();
+}
+
+SimpleTest.waitForExplicitFinish();
+
+</script>
+
+</head>
+
+<body onload="startTest();">
+
+</body>
+</html>
diff --git a/dom/tests/mochitest/localstorage/test_bug746272-2.html b/dom/tests/mochitest/localstorage/test_bug746272-2.html
new file mode 100644
index 0000000000..31edbc906a
--- /dev/null
+++ b/dom/tests/mochitest/localstorage/test_bug746272-2.html
@@ -0,0 +1,31 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<title>incomplete UTF-16 test</title>
+<meta http-equiv="Content-type" content="text/html; charset=UTF-8" />
+
+<script src="/tests/SimpleTest/SimpleTest.js"></script>
+<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+
+<script type="text/javascript">
+
+function startTest()
+{
+ var test2 = localStorage.getItem("test2");
+ is(test2, "value2", "expected item");
+
+ localStorage.removeItem("test2");
+ is(localStorage.length, 2, "expected number of items");
+
+ SimpleTest.finish();
+}
+
+SimpleTest.waitForExplicitFinish();
+
+</script>
+
+</head>
+
+<body onload="startTest();">
+
+</body>
+</html>
diff --git a/dom/tests/mochitest/localstorage/test_cookieBlock.html b/dom/tests/mochitest/localstorage/test_cookieBlock.html
new file mode 100644
index 0000000000..9cc7495d40
--- /dev/null
+++ b/dom/tests/mochitest/localstorage/test_cookieBlock.html
@@ -0,0 +1,53 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<title>cookie blocking test</title>
+
+<script src="/tests/SimpleTest/SimpleTest.js"></script>
+<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+
+<script type="text/javascript">
+
+function startTest()
+{
+ // Let's use a new window to have the cookie permission applied.
+ let w = window.open("windowProxy.html");
+ w.onload = _ => {
+ try {
+ w.localStorage.setItem("blocked", "blockedvalue");
+ ok(false, "Exception for localStorage.setItem, ACCESS_DENY");
+ }
+ catch (ex) {
+ ok(true, "Exception for localStorage.setItem, ACCESS_DENY");
+ }
+
+ try {
+ w.localStorage.getItem("blocked");
+ ok(false, "Exception for localStorage.getItem, ACCESS_DENY");
+ }
+ catch (ex) {
+ ok(true, "Exception for localStorage.getItem, ACCESS_DENY");
+ }
+
+ w.close();
+ SpecialPowers.popPermissions(() => {
+ SimpleTest.finish();
+ });
+ }
+}
+
+SimpleTest.waitForExplicitFinish();
+
+// Initialize storage before setting the cookie, otherwise we won't be testing
+// the checks in setItem/getItem methods.
+var storage = localStorage;
+
+SpecialPowers.pushPermissions([{'type': 'cookie', 'allow': false, 'context': document}], startTest);
+
+</script>
+
+</head>
+
+<body>
+
+</body>
+</html>
diff --git a/dom/tests/mochitest/localstorage/test_embededNulls.html b/dom/tests/mochitest/localstorage/test_embededNulls.html
new file mode 100644
index 0000000000..b12a403b85
--- /dev/null
+++ b/dom/tests/mochitest/localstorage/test_embededNulls.html
@@ -0,0 +1,40 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<title>embeded nulls test</title>
+
+<script src="/tests/SimpleTest/SimpleTest.js"></script>
+<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+
+<script type="text/javascript">
+
+function startTest()
+{
+ var k = "key with\x00null";
+ var v = "value with\x00null";
+
+ localStorage.setItem(k, v);
+
+ is(localStorage.getItem("key with"), null,
+ "not accessible by truncated key");
+
+ is(localStorage.getItem(k), "value with\x00null",
+ "value is identical to what has been stored");
+
+ isnot(localStorage.getItem(k), "value with",
+ "value is not truncated");
+
+ localStorage.clear();
+
+ SimpleTest.finish();
+}
+
+SimpleTest.waitForExplicitFinish();
+
+</script>
+
+</head>
+
+<body onload="startTest();">
+
+</body>
+</html>
diff --git a/dom/tests/mochitest/localstorage/test_keySync.html b/dom/tests/mochitest/localstorage/test_keySync.html
new file mode 100644
index 0000000000..3f23945e2f
--- /dev/null
+++ b/dom/tests/mochitest/localstorage/test_keySync.html
@@ -0,0 +1,33 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<title>localStorage equal origins</title>
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="interOriginTest2.js"></script>
+
+<!--
+ This test loads two frames from the same origin, clears in one frame,
+ sets a single key in another and then checks key(0) in the first frame.
+-->
+
+<script type="text/javascript">
+
+function startTest()
+{
+ masterFrameOrigin = "http://example.org:80";
+ slaveFrameOrigin = "http://example.org:80";
+
+ masterFrame.location = masterFrameOrigin + framePath + "frameKeySync.html?1";
+ slaveFrame.location = slaveFrameOrigin + framePath + "frameKeySync.html?2";
+}
+
+</script>
+
+</head>
+
+<body onload="startTest();">
+ <iframe src="" name="masterFrame"></iframe>
+ <iframe src="" name="slaveFrame"></iframe>
+</body>
+</html>
diff --git a/dom/tests/mochitest/localstorage/test_localStorageBase.html b/dom/tests/mochitest/localstorage/test_localStorageBase.html
new file mode 100644
index 0000000000..a906b42a63
--- /dev/null
+++ b/dom/tests/mochitest/localstorage/test_localStorageBase.html
@@ -0,0 +1,247 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<title>localStorage basic test</title>
+
+<script src="/tests/SimpleTest/SimpleTest.js"></script>
+<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+
+<script type="text/javascript">
+
+var expectedEvents = [
+ "empty,null,",
+ "empty,,null",
+ "key1,null,value1",
+ "key1,value1,null",
+ "key1,null,value1",
+ "key2,null,value2",
+ "key2,value2,value2-2",
+ "key1,value1,value1-2",
+ "key2,value2-2,null",
+ "testA,null,valueA",
+ "testA,valueA,valueA2",
+ "testB,null,valueB",
+ "testB,valueB,valueB2",
+ "testC,null,valueC",
+ "testC,valueC,valueC2",
+ "testC,valueC2,null",
+ "testC,null,null",
+ "testC,null,null",
+ "null,null,test",
+ "null,test,null",
+ "null,null,test",
+ "null,test,null",
+ "null,null,null"
+];
+
+function startTest()
+{
+ // Initially check the localStorage is empty
+ is(localStorage.length, 0, "The storage is empty [1]");
+ is(localStorage.key(0), null, "key() should return null for out-of-bounds access");
+ is(localStorage.key(-1), null, "key() should return null for out-of-bounds access");
+ is(localStorage.key(1), null, "key() should return null for out-of-bounds access");
+ is(localStorage.getItem("nonexisting"), null, "Nonexisting item is null (getItem())");
+ is(localStorage.nonexisting, undefined, "Nonexisting item is undefined (array access)");
+ is(localStorage.nonexisting, undefined, "Nonexisting item is undefined (property access)");
+ localStorage.removeItem("nonexisting"); // Just check there is no exception
+
+ is(typeof localStorage.getItem("nonexisting"), "object", "getItem('nonexisting') is object");
+ is(typeof localStorage.nonexisting, "undefined", "['nonexisting'] is undefined");
+ is(typeof localStorage.nonexisting, "undefined", "nonexisting is undefined");
+ is(typeof localStorage.getItem("nonexisting2"), "object", "getItem('nonexisting2') is object");
+ is(typeof localStorage.nonexisting2, "undefined", "['nonexisting2'] is undefined");
+ is(typeof localStorage.nonexisting2, "undefined", "nonexisting2 is undefined");
+
+ var localStorageCopy = localStorage;
+
+ function onStorageChanged(e) {
+ if (e.storageArea == localStorageCopy) {
+ ok(expectedEvents.length, "Not more then expected events encountered");
+ var receivedEvent = e.key + "," + e.oldValue + "," + e.newValue;
+ is(receivedEvent, expectedEvents.shift(), "Expected event data: " + receivedEvent);
+ }
+ }
+
+ // Listen for MozLocalStorageChanged
+ SpecialPowers.addChromeEventListener("MozLocalStorageChanged", onStorageChanged, true);
+
+ // add an empty-value key
+ localStorage.setItem("empty", "");
+ is(localStorage.getItem("empty"), "", "Empty value (getItem())");
+ is(localStorage.empty, "", "Empty value (array access)");
+ is(localStorage.empty, "", "Empty value (property access)");
+ is(typeof localStorage.getItem("empty"), "string", "getItem('empty') is string");
+ is(typeof localStorage.empty, "string", "['empty'] is string");
+ is(typeof localStorage.empty, "string", "empty is string");
+ localStorage.removeItem("empty");
+ is(localStorage.length, 0, "The storage has no keys");
+ is(localStorage.getItem("empty"), null, "empty item is null (getItem())");
+ is(localStorage.empty, undefined, "empty item is undefined (array access)");
+ is(localStorage.empty, undefined, "empty item is undefined (property access)");
+ is(typeof localStorage.getItem("empty"), "object", "getItem('empty') is object");
+ is(typeof localStorage.empty, "undefined", "['empty'] is undefined");
+ is(typeof localStorage.empty, "undefined", "empty is undefined");
+
+ // add one key, check it is there
+ localStorage.setItem("key1", "value1");
+ is(localStorage.length, 1, "The storage has one key-value pair");
+ is(localStorage.key(0), "key1");
+ is(localStorage.key(-1), null, "key() should return null for out-of-bounds access");
+ is(localStorage.key(1), null, "key() should return null for out-of-bounds access");
+
+ // check all access method give the correct result
+ // and are of the correct type
+ is(localStorage.getItem("key1"), "value1", "getItem('key1') == value1");
+ is(localStorage.key1, "value1", "['key1'] == value1");
+ is(localStorage.key1, "value1", "key1 == value1");
+
+ is(typeof localStorage.getItem("key1"), "string", "getItem('key1') is string");
+ is(typeof localStorage.key1, "string", "['key1'] is string");
+ is(typeof localStorage.key1, "string", "key1 is string");
+
+ // remove the previously added key and check the storage is empty
+ localStorage.removeItem("key1");
+ is(localStorage.length, 0, "The storage is empty [2]");
+ is(localStorage.key(0), null, "key() should return null for out-of-bounds access");
+ is(localStorage.getItem("key1"), null, "\'key1\' removed");
+
+ is(typeof localStorage.getItem("key1"), "object", "getItem('key1') is object");
+ is(typeof localStorage.key1, "undefined", "['key1'] is object");
+ is(typeof localStorage.key1, "undefined", "key1 is object");
+
+ // add one key, check it is there
+ localStorage.setItem("key1", "value1");
+ is(localStorage.length, 1, "The storage has one key-value pair");
+ is(localStorage.key(0), "key1");
+ is(localStorage.getItem("key1"), "value1");
+
+ // add a second key
+ localStorage.setItem("key2", "value2");
+ is(localStorage.length, 2, "The storage has two key-value pairs");
+ is(localStorage.getItem("key1"), "value1");
+ is(localStorage.getItem("key2"), "value2");
+ var firstKey = localStorage.key(0);
+ var secondKey = localStorage.key(1);
+ ok((firstKey == 'key1' && secondKey == 'key2') ||
+ (firstKey == 'key2' && secondKey == 'key1'),
+ 'key() API works.');
+
+ // change the second key
+ localStorage.setItem("key2", "value2-2");
+ is(localStorage.length, 2, "The storage has two key-value pairs");
+ is(localStorage.key(0), firstKey); // After key value changes the order must be preserved
+ is(localStorage.key(1), secondKey);
+ is(localStorage.key(-1), null, "key() should return null for out-of-bounds access");
+ is(localStorage.key(2), null, "key() should return null for out-of-bounds access");
+ is(localStorage.getItem("key1"), "value1");
+ is(localStorage.getItem("key2"), "value2-2");
+
+ // change the first key
+ localStorage.setItem("key1", "value1-2");
+ is(localStorage.length, 2, "The storage has two key-value pairs");
+ is(localStorage.key(0), firstKey); // After key value changes the order must be preserved
+ is(localStorage.key(1), secondKey);
+ is(localStorage.key(-1), null, "key() should return null for out-of-bounds access");
+ is(localStorage.key(2), null, "key() should return null for out-of-bounds access");
+ is(localStorage.getItem("key1"), "value1-2");
+ is(localStorage.getItem("key2"), "value2-2");
+
+ // remove the second key
+ localStorage.removeItem("key2");
+ is(localStorage.length, 1, "The storage has one key-value pair");
+ is(localStorage.key(0), "key1");
+ is(localStorage.key(-1), null, "key() should return null for out-of-bounds access");
+ is(localStorage.key(1), null, "key() should return null for out-of-bounds access");
+ is(localStorage.getItem("key1"), "value1-2");
+
+ // JS property test
+ localStorage.testA = "valueA";
+ is(localStorage.testA, "valueA");
+ is(localStorage.testA, "valueA");
+ is(localStorage.getItem("testA"), "valueA");
+
+ localStorage.testA = "valueA2";
+ is(localStorage.testA, "valueA2");
+ is(localStorage.testA, "valueA2");
+ is(localStorage.getItem("testA"), "valueA2");
+
+ localStorage.testB = "valueB";
+ is(localStorage.testB, "valueB");
+ is(localStorage.testB, "valueB");
+ is(localStorage.getItem("testB"), "valueB");
+
+ localStorage.testB = "valueB2";
+ is(localStorage.testB, "valueB2");
+ is(localStorage.testB, "valueB2");
+ is(localStorage.getItem("testB"), "valueB2");
+
+ localStorage.setItem("testC", "valueC");
+ is(localStorage.testC, "valueC");
+ is(localStorage.testC, "valueC");
+ is(localStorage.getItem("testC"), "valueC");
+
+ localStorage.setItem("testC", "valueC2");
+ is(localStorage.testC, "valueC2");
+ is(localStorage.testC, "valueC2");
+ is(localStorage.getItem("testC"), "valueC2");
+
+ localStorage.setItem("testC", null);
+ is("testC" in localStorage, true);
+ is(localStorage.getItem("testC"), "null");
+ is(localStorage.testC, "null");
+ is(localStorage.testC, "null");
+
+ localStorage.removeItem("testC");
+ localStorage.testC = null;
+ is("testC" in localStorage, true);
+ is(localStorage.getItem("testC"), "null");
+ is(localStorage.testC, "null");
+ is(localStorage.testC, "null");
+
+ localStorage.setItem(null, "test");
+ is("null" in localStorage, true);
+ is(localStorage.getItem("null"), "test");
+ is(localStorage.getItem(null), "test");
+ is(localStorage.null, "test");
+ localStorage.removeItem(null, "test");
+ is("null" in localStorage, false);
+
+ localStorage.setItem(null, "test");
+ is("null" in localStorage, true);
+ localStorage.removeItem("null", "test");
+ is("null" in localStorage, false);
+
+ // Clear the storage
+ localStorage.clear();
+ is("testB" in localStorage, false, "Keys are not in the JS scope of the storage");
+ is("testC" in localStorage, false, "Keys are not in the JS scope of the storage");
+ is(localStorage.length, 0, "The storage is empty [3]");
+ is(localStorage.key(0), null, "key() should return null for out-of-bounds access");
+ is(localStorage.key(-1), null, "key() should return null for out-of-bounds access");
+ is(localStorage.key(1), null, "key() should return null for out-of-bounds access");
+ is(localStorage.getItem("nonexisting"), null, "Nonexisting item is null");
+ is(localStorage.getItem("key1"), null, "key1 removed");
+ is(localStorage.getItem("key2"), null, "key2 removed");
+ localStorage.removeItem("nonexisting"); // Just check there is no exception
+ localStorage.removeItem("key1"); // Just check there is no exception
+ localStorage.removeItem("key2"); // Just check there is no exception
+
+ SimpleTest.executeSoon(function () {
+ SpecialPowers.removeChromeEventListener("MozLocalStorageChanged", onStorageChanged, true);
+ is(expectedEvents.length, 0, "received the correct number of events");
+
+ localStorage.clear();
+ SimpleTest.finish();
+ });
+}
+
+SimpleTest.waitForExplicitFinish();
+
+</script>
+
+</head>
+
+<body onload="startTest();">
+
+</body>
+</html>
diff --git a/dom/tests/mochitest/localstorage/test_localStorageBasePrivateBrowsing_perwindowpb.html b/dom/tests/mochitest/localstorage/test_localStorageBasePrivateBrowsing_perwindowpb.html
new file mode 100644
index 0000000000..1bf1f4450e
--- /dev/null
+++ b/dom/tests/mochitest/localstorage/test_localStorageBasePrivateBrowsing_perwindowpb.html
@@ -0,0 +1,256 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<title>localStorage basic test, while in sesison only mode</title>
+
+<script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"?>
+
+<script type="text/javascript">
+
+var mainWindow;
+
+var prefBranch = Cc["@mozilla.org/preferences-service;1"]
+ .getService(Ci.nsIPrefBranch);
+prefBranch.setIntPref("browser.startup.page", 0);
+prefBranch.setCharPref("browser.startup.homepage_override.mstone", "ignore");
+
+function startTest() {
+ mainWindow = window.browsingContext.topChromeWindow;
+
+ doTest();
+}
+
+var contentPage = "http://mochi.test:8888/chrome/dom/tests/mochitest/localstorage/page_blank.html";
+
+function testOnWindow(aIsPrivate, aCallback) {
+ var win = mainWindow.OpenBrowserWindow({private: aIsPrivate});
+ win.addEventListener("load", function() {
+ win.addEventListener("DOMContentLoaded", function onInnerLoad() {
+ if (win.content.location.href == "about:privatebrowsing") {
+ win.gBrowser.loadURI(Services.io.newURI(contentPage));
+ return;
+ }
+ win.removeEventListener("DOMContentLoaded", onInnerLoad, true);
+ SimpleTest.executeSoon(function() { aCallback(win); });
+ }, true);
+ win.gBrowser.loadURI(Services.io.newURI(contentPage));
+ }, {capture: true, once: true});
+}
+
+function doTest() {
+ testOnWindow(false, function(aWin) {
+ aWin.content.localStorage.setItem("persistent", "persistent1");
+
+ testOnWindow(true, function(privateWin) {
+ is(privateWin.content.localStorage.getItem("persistent"), null, "previous values are inaccessible");
+
+ // Initially check the privateWin.content.localStorage is empty
+ is(privateWin.content.localStorage.length, 0, "The storage is empty [1]");
+ is(privateWin.content.localStorage.key(0), null, "key() should return null for out-of-bounds access");
+ is(privateWin.content.localStorage.key(-1), null, "key() should return null for out-of-bounds access");
+ is(privateWin.content.localStorage.key(1), null, "key() should return null for out-of-bounds access");
+ is(privateWin.content.localStorage.getItem("nonexisting"), null, "Nonexisting item is null (getItem())");
+ is(privateWin.content.localStorage.nonexisting, undefined, "Nonexisting item is null (array access)");
+ is(privateWin.content.localStorage.nonexisting, undefined, "Nonexisting item is null (property access)");
+ privateWin.content.localStorage.removeItem("nonexisting"); // Just check there is no exception
+
+ is(typeof privateWin.content.localStorage.getItem("nonexisting"), "object", "getItem('nonexisting') is object");
+ is(typeof privateWin.content.localStorage.nonexisting, "undefined", "['nonexisting'] is undefined");
+ is(typeof privateWin.content.localStorage.nonexisting, "undefined", "nonexisting is undefined");
+ is(typeof privateWin.content.localStorage.getItem("nonexisting2"), "object", "getItem('nonexisting2') is object");
+ is(typeof privateWin.content.localStorage.nonexisting2, "undefined", "['nonexisting2'] is undefined");
+ is(typeof privateWin.content.localStorage.nonexisting2, "undefined", "nonexisting2 is undefined");
+
+ // add an empty-value key
+ privateWin.content.localStorage.setItem("empty", "");
+ is(privateWin.content.localStorage.getItem("empty"), "", "Empty value (getItem())");
+ is(privateWin.content.localStorage.empty, "", "Empty value (array access)");
+ is(privateWin.content.localStorage.empty, "", "Empty value (property access)");
+ is(typeof privateWin.content.localStorage.getItem("empty"), "string", "getItem('empty') is string");
+ is(typeof privateWin.content.localStorage.empty, "string", "['empty'] is string");
+ is(typeof privateWin.content.localStorage.empty, "string", "empty is string");
+ privateWin.content.localStorage.removeItem("empty");
+ is(privateWin.content.localStorage.length, 0, "The storage has no keys");
+ is(privateWin.content.localStorage.getItem("empty"), null, "empty item is null (getItem())");
+ is(privateWin.content.localStorage.empty, undefined, "empty item is undefined (array access)");
+ is(privateWin.content.localStorage.empty, undefined, "empty item is undefined (property access)");
+ is(typeof privateWin.content.localStorage.getItem("empty"), "object", "getItem('empty') is object");
+ is(typeof privateWin.content.localStorage.empty, "undefined", "['empty'] is undefined");
+ is(typeof privateWin.content.localStorage.empty, "undefined", "empty is undefined");
+
+ // add one key, check it is there
+ privateWin.content.localStorage.setItem("key1", "value1");
+ is(privateWin.content.localStorage.length, 1, "The storage has one key-value pair");
+ is(privateWin.content.localStorage.key(0), "key1");
+ is(privateWin.content.localStorage.key(-1), null, "key() should return null for out-of-bounds access");
+ is(privateWin.content.localStorage.key(1), null, "key() should return null for out-of-bounds access");
+
+ // check all access method give the correct result
+ // and are of the correct type
+ is(privateWin.content.localStorage.getItem("key1"), "value1", "getItem('key1') == value1");
+ is(privateWin.content.localStorage.key1, "value1", "['key1'] == value1");
+ is(privateWin.content.localStorage.key1, "value1", "key1 == value1");
+
+ is(typeof privateWin.content.localStorage.getItem("key1"), "string", "getItem('key1') is string");
+ is(typeof privateWin.content.localStorage.key1, "string", "['key1'] is string");
+ is(typeof privateWin.content.localStorage.key1, "string", "key1 is string");
+
+ // remove the previously added key and check the storage is empty
+ privateWin.content.localStorage.removeItem("key1");
+ is(privateWin.content.localStorage.length, 0, "The storage is empty [2]");
+ is(privateWin.content.localStorage.key(0), null, "key() should return null for out-of-bounds access");
+ is(privateWin.content.localStorage.getItem("key1"), null, "\'key1\' removed");
+
+ is(typeof privateWin.content.localStorage.getItem("key1"), "object", "getItem('key1') is object");
+ is(typeof privateWin.content.localStorage.key1, "undefined", "['key1'] is undefined");
+ is(typeof privateWin.content.localStorage.key1, "undefined", "key1 is undefined");
+
+ // add one key, check it is there
+ privateWin.content.localStorage.setItem("key1", "value1");
+ is(privateWin.content.localStorage.length, 1, "The storage has one key-value pair");
+ is(privateWin.content.localStorage.key(0), "key1");
+ is(privateWin.content.localStorage.getItem("key1"), "value1");
+
+ // add a second key
+ privateWin.content.localStorage.setItem("key2", "value2");
+ is(privateWin.content.localStorage.length, 2, "The storage has two key-value pairs");
+ is(privateWin.content.localStorage.getItem("key1"), "value1");
+ is(privateWin.content.localStorage.getItem("key2"), "value2");
+ var firstKey = privateWin.content.localStorage.key(0);
+ var secondKey = privateWin.content.localStorage.key(1);
+ ok((firstKey == 'key1' && secondKey == 'key2') ||
+ (firstKey == 'key2' && secondKey == 'key1'),
+ 'key() API works.');
+
+ // change the second key
+ privateWin.content.localStorage.setItem("key2", "value2-2");
+ is(privateWin.content.localStorage.length, 2, "The storage has two key-value pairs");
+ is(privateWin.content.localStorage.key(0), firstKey); // After key value changes the order must be preserved
+ is(privateWin.content.localStorage.key(1), secondKey);
+ is(privateWin.content.localStorage.key(-1), null, "key() should return null for out-of-bounds access");
+ is(privateWin.content.localStorage.key(2), null, "key() should return null for out-of-bounds access");
+ is(privateWin.content.localStorage.getItem("key1"), "value1");
+ is(privateWin.content.localStorage.getItem("key2"), "value2-2");
+
+ // change the first key
+ privateWin.content.localStorage.setItem("key1", "value1-2");
+ is(privateWin.content.localStorage.length, 2, "The storage has two key-value pairs");
+ is(privateWin.content.localStorage.key(0), firstKey); // After key value changes the order must be preserved
+ is(privateWin.content.localStorage.key(1), secondKey);
+ is(privateWin.content.localStorage.key(-1), null, "key() should return null for out-of-bounds access");
+ is(privateWin.content.localStorage.key(2), null, "key() should return null for out-of-bounds access");
+ is(privateWin.content.localStorage.getItem("key1"), "value1-2");
+ is(privateWin.content.localStorage.getItem("key2"), "value2-2");
+
+ // remove the second key
+ privateWin.content.localStorage.removeItem("key2");
+ is(privateWin.content.localStorage.length, 1, "The storage has one key-value pair");
+ is(privateWin.content.localStorage.key(0), "key1");
+ is(privateWin.content.localStorage.key(-1), null, "key() should return null for out-of-bounds access");
+ is(privateWin.content.localStorage.key(1), null, "key() should return null for out-of-bounds access");
+ is(privateWin.content.localStorage.getItem("key1"), "value1-2");
+
+ // JS property test
+ privateWin.content.localStorage.testA = "valueA";
+ is(privateWin.content.localStorage.testA, "valueA");
+ is(privateWin.content.localStorage.testA, "valueA");
+ is(privateWin.content.localStorage.getItem("testA"), "valueA");
+
+ privateWin.content.localStorage.testA = "valueA2";
+ is(privateWin.content.localStorage.testA, "valueA2");
+ is(privateWin.content.localStorage.testA, "valueA2");
+ is(privateWin.content.localStorage.getItem("testA"), "valueA2");
+
+ privateWin.content.localStorage.testB = "valueB";
+ is(privateWin.content.localStorage.testB, "valueB");
+ is(privateWin.content.localStorage.testB, "valueB");
+ is(privateWin.content.localStorage.getItem("testB"), "valueB");
+
+ privateWin.content.localStorage.testB = "valueB2";
+ is(privateWin.content.localStorage.testB, "valueB2");
+ is(privateWin.content.localStorage.testB, "valueB2");
+ is(privateWin.content.localStorage.getItem("testB"), "valueB2");
+
+ privateWin.content.localStorage.setItem("testC", "valueC");
+ is(privateWin.content.localStorage.testC, "valueC");
+ is(privateWin.content.localStorage.testC, "valueC");
+ is(privateWin.content.localStorage.getItem("testC"), "valueC");
+
+ privateWin.content.localStorage.setItem("testC", "valueC2");
+ is(privateWin.content.localStorage.testC, "valueC2");
+ is(privateWin.content.localStorage.testC, "valueC2");
+ is(privateWin.content.localStorage.getItem("testC"), "valueC2");
+
+ privateWin.content.localStorage.setItem("testC", null);
+ is("testC" in privateWin.content.localStorage, true);
+ is(privateWin.content.localStorage.getItem("testC"), "null");
+ is(privateWin.content.localStorage.testC, "null");
+ is(privateWin.content.localStorage.testC, "null");
+
+ privateWin.content.localStorage.removeItem("testC");
+ privateWin.content.localStorage.testC = null;
+ is("testC" in privateWin.content.localStorage, true);
+ is(privateWin.content.localStorage.getItem("testC"), "null");
+ is(privateWin.content.localStorage.testC, "null");
+ is(privateWin.content.localStorage.testC, "null");
+
+ privateWin.content.localStorage.setItem(null, "test");
+ is("null" in privateWin.content.localStorage, true);
+ is(privateWin.content.localStorage.getItem("null"), "test");
+ is(privateWin.content.localStorage.getItem(null), "test");
+ is(privateWin.content.localStorage.null, "test");
+ privateWin.content.localStorage.removeItem(null, "test");
+ is("null" in privateWin.content.localStorage, false);
+
+ privateWin.content.localStorage.setItem(null, "test");
+ is("null" in privateWin.content.localStorage, true);
+ privateWin.content.localStorage.removeItem("null", "test");
+ is("null" in privateWin.content.localStorage, false);
+
+ // Clear the storage
+ privateWin.content.localStorage.clear();
+ is(privateWin.content.localStorage.length, 0, "The storage is empty [3]");
+ is(privateWin.content.localStorage.key(0), null, "key() should return null for out-of-bounds access");
+ is(privateWin.content.localStorage.key(-1), null, "key() should return null for out-of-bounds access");
+ is(privateWin.content.localStorage.key(1), null, "key() should return null for out-of-bounds access");
+ is(privateWin.content.localStorage.getItem("nonexisting"), null, "Nonexisting item is null");
+ is(privateWin.content.localStorage.getItem("key1"), null, "key1 removed");
+ is(privateWin.content.localStorage.getItem("key2"), null, "key2 removed");
+ privateWin.content.localStorage.removeItem("nonexisting"); // Just check there is no exception
+ privateWin.content.localStorage.removeItem("key1"); // Just check there is no exception
+ privateWin.content.localStorage.removeItem("key2"); // Just check there is no exception
+
+ privateWin.content.localStorage.setItem("must disappear", "private browsing value");
+
+ privateWin.close();
+
+ // The .close() call above will operate asynchronously, so execute the
+ // code below asynchronously as well.
+ function callback(newPrivateWin) {
+ is(newPrivateWin.content.localStorage.getItem("must disappear"), null, "private browsing values threw away");
+ is(newPrivateWin.content.localStorage.length, 0, "No items");
+
+ newPrivateWin.close();
+ is(aWin.content.localStorage.getItem("persistent"), "persistent1", "back in normal mode");
+ aWin.content.localStorage.clear();
+ aWin.close();
+
+ prefBranch.clearUserPref("browser.startup.page")
+ prefBranch.clearUserPref("browser.startup.homepage_override.mstone");
+ SimpleTest.finish();
+ };
+ SimpleTest.executeSoon(() => testOnWindow(true, callback));
+ });
+ });
+}
+
+SimpleTest.waitForExplicitFinish();
+
+</script>
+
+</head>
+
+<body onload="startTest();">
+
+</body>
+</html>
diff --git a/dom/tests/mochitest/localstorage/test_localStorageBaseSessionOnly.html b/dom/tests/mochitest/localstorage/test_localStorageBaseSessionOnly.html
new file mode 100644
index 0000000000..39df8ac519
--- /dev/null
+++ b/dom/tests/mochitest/localstorage/test_localStorageBaseSessionOnly.html
@@ -0,0 +1,211 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<title>localStorage basic test, while in sesison only mode</title>
+
+<script src="/tests/SimpleTest/SimpleTest.js"></script>
+<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+
+<script type="text/javascript">
+
+function startTest()
+{
+ if (SpecialPowers.Services.domStorageManager.nextGenLocalStorageEnabled) {
+ ok(true, "Test ignored when the next gen local storage is enabled.");
+ SimpleTest.finish();
+ return;
+ }
+
+ SpecialPowers.pushPermissions([{'type': 'cookie', 'allow': SpecialPowers.Ci.nsICookiePermission.ACCESS_SESSION, 'context': document}], test1);
+}
+
+function test1() {
+ // Initially check the localStorage is empty
+ is(localStorage.length, 0, "The storage is empty [1]");
+ is(localStorage.key(0), null, "key() should return null for out-of-bounds access");
+ is(localStorage.key(-1), null, "key() should return null for out-of-bounds access");
+ is(localStorage.key(1), null, "key() should return null for out-of-bounds access");
+ is(localStorage.getItem("nonexisting"), null, "Nonexisting item is null (getItem())");
+ is(localStorage.nonexisting, undefined, "Nonexisting item is undefined (array access)");
+ is(localStorage.nonexisting, undefined, "Nonexisting item is undefined (property access)");
+ localStorage.removeItem("nonexisting"); // Just check there is no exception
+
+ is(typeof localStorage.getItem("nonexisting"), "object", "getItem('nonexisting') is object");
+ is(typeof localStorage.nonexisting, "undefined", "['nonexisting'] is undefined");
+ is(typeof localStorage.nonexisting, "undefined", "nonexisting is undefined");
+ is(typeof localStorage.getItem("nonexisting2"), "object", "getItem('nonexisting2') is object");
+ is(typeof localStorage.nonexisting2, "undefined", "['nonexisting2'] is undefined");
+ is(typeof localStorage.nonexisting2, "undefined", "nonexisting2 is undefined");
+
+ // add an empty-value key
+ localStorage.setItem("empty", "");
+ is(localStorage.getItem("empty"), "", "Empty value (getItem())");
+ is(localStorage.empty, "", "Empty value (array access)");
+ is(localStorage.empty, "", "Empty value (property access)");
+ is(typeof localStorage.getItem("empty"), "string", "getItem('empty') is string");
+ is(typeof localStorage.empty, "string", "['empty'] is string");
+ is(typeof localStorage.empty, "string", "empty is string");
+ localStorage.removeItem("empty");
+ is(localStorage.length, 0, "The storage has no keys");
+ is(localStorage.getItem("empty"), null, "empty item is null (getItem())");
+ is(localStorage.empty, undefined, "empty item is undefined (array access)");
+ is(localStorage.empty, undefined, "empty item is undefined (property access)");
+ is(typeof localStorage.getItem("empty"), "object", "getItem('empty') is object");
+ is(typeof localStorage.empty, "undefined", "['empty'] is undefined");
+ is(typeof localStorage.empty, "undefined", "empty is undefined");
+
+ // add one key, check it is there
+ localStorage.setItem("key1", "value1");
+ is(localStorage.length, 1, "The storage has one key-value pair");
+ is(localStorage.key(0), "key1");
+ is(localStorage.key(-1), null, "key() should return null for out-of-bounds access");
+ is(localStorage.key(1), null, "key() should return null for out-of-bounds access");
+
+ // check all access method give the correct result
+ // and are of the correct type
+ is(localStorage.getItem("key1"), "value1", "getItem('key1') == value1");
+ is(localStorage.key1, "value1", "['key1'] == value1");
+ is(localStorage.key1, "value1", "key1 == value1");
+
+ is(typeof localStorage.getItem("key1"), "string", "getItem('key1') is string");
+ is(typeof localStorage.key1, "string", "['key1'] is string");
+ is(typeof localStorage.key1, "string", "key1 is string");
+
+ // remove the previously added key and check the storage is empty
+ localStorage.removeItem("key1");
+ is(localStorage.length, 0, "The storage is empty [2]");
+ is(localStorage.key(0), null, "key() should return null for out-of-bounds access");
+ is(localStorage.getItem("key1"), null, "\'key1\' removed");
+
+ is(typeof localStorage.getItem("key1"), "object", "getItem('key1') is object");
+ is(typeof localStorage.key1, "undefined", "['key1'] is undefined");
+ is(typeof localStorage.key1, "undefined", "key1 is undefined");
+
+ // add one key, check it is there
+ localStorage.setItem("key1", "value1");
+ is(localStorage.length, 1, "The storage has one key-value pair");
+ is(localStorage.key(0), "key1");
+ is(localStorage.getItem("key1"), "value1");
+
+ // add a second key
+ localStorage.setItem("key2", "value2");
+ is(localStorage.length, 2, "The storage has two key-value pairs");
+ is(localStorage.getItem("key1"), "value1");
+ is(localStorage.getItem("key2"), "value2");
+ var firstKey = localStorage.key(0);
+ var secondKey = localStorage.key(1);
+ ok((firstKey == 'key1' && secondKey == 'key2') ||
+ (firstKey == 'key2' && secondKey == 'key1'),
+ 'key() API works.');
+
+ // change the second key
+ localStorage.setItem("key2", "value2-2");
+ is(localStorage.length, 2, "The storage has two key-value pairs");
+ is(localStorage.key(0), firstKey); // After key value changes the order must be preserved
+ is(localStorage.key(1), secondKey);
+ is(localStorage.key(-1), null, "key() should return null for out-of-bounds access");
+ is(localStorage.key(2), null, "key() should return null for out-of-bounds access");
+ is(localStorage.getItem("key1"), "value1");
+ is(localStorage.getItem("key2"), "value2-2");
+
+ // change the first key
+ localStorage.setItem("key1", "value1-2");
+ is(localStorage.length, 2, "The storage has two key-value pairs");
+ is(localStorage.key(0), firstKey); // After key value changes the order must be preserved
+ is(localStorage.key(1), secondKey);
+ is(localStorage.key(-1), null, "key() should return null for out-of-bounds access");
+ is(localStorage.key(2), null, "key() should return null for out-of-bounds access");
+ is(localStorage.getItem("key1"), "value1-2");
+ is(localStorage.getItem("key2"), "value2-2");
+
+ // remove the second key
+ localStorage.removeItem("key2");
+ is(localStorage.length, 1, "The storage has one key-value pair");
+ is(localStorage.key(0), "key1");
+ is(localStorage.key(-1), null, "key() should return null for out-of-bounds access");
+ is(localStorage.key(1), null, "key() should return null for out-of-bounds access");
+ is(localStorage.getItem("key1"), "value1-2");
+
+ // JS property test
+ localStorage.testA = "valueA";
+ is(localStorage.testA, "valueA");
+ is(localStorage.testA, "valueA");
+ is(localStorage.getItem("testA"), "valueA");
+
+ localStorage.testA = "valueA2";
+ is(localStorage.testA, "valueA2");
+ is(localStorage.testA, "valueA2");
+ is(localStorage.getItem("testA"), "valueA2");
+
+ localStorage.testB = "valueB";
+ is(localStorage.testB, "valueB");
+ is(localStorage.testB, "valueB");
+ is(localStorage.getItem("testB"), "valueB");
+
+ localStorage.testB = "valueB2";
+ is(localStorage.testB, "valueB2");
+ is(localStorage.testB, "valueB2");
+ is(localStorage.getItem("testB"), "valueB2");
+
+ localStorage.setItem("testC", "valueC");
+ is(localStorage.testC, "valueC");
+ is(localStorage.testC, "valueC");
+ is(localStorage.getItem("testC"), "valueC");
+
+ localStorage.setItem("testC", "valueC2");
+ is(localStorage.testC, "valueC2");
+ is(localStorage.testC, "valueC2");
+ is(localStorage.getItem("testC"), "valueC2");
+
+ localStorage.setItem("testC", null);
+ is("testC" in localStorage, true);
+ is(localStorage.getItem("testC"), "null");
+ is(localStorage.testC, "null");
+ is(localStorage.testC, "null");
+
+ localStorage.removeItem("testC");
+ localStorage.testC = null;
+ is("testC" in localStorage, true);
+ is(localStorage.getItem("testC"), "null");
+ is(localStorage.testC, "null");
+ is(localStorage.testC, "null");
+
+ localStorage.setItem(null, "test");
+ is("null" in localStorage, true);
+ is(localStorage.getItem("null"), "test");
+ is(localStorage.getItem(null), "test");
+ is(localStorage.null, "test");
+ localStorage.removeItem(null, "test");
+ is("null" in localStorage, false);
+
+ localStorage.setItem(null, "test");
+ is("null" in localStorage, true);
+ localStorage.removeItem("null", "test");
+ is("null" in localStorage, false);
+
+ // Clear the storage
+ localStorage.clear();
+ is(localStorage.length, 0, "The storage is empty [3]");
+ is(localStorage.key(0), null, "key() should return null for out-of-bounds access");
+ is(localStorage.key(-1), null, "key() should return null for out-of-bounds access");
+ is(localStorage.key(1), null, "key() should return null for out-of-bounds access");
+ is(localStorage.getItem("nonexisting"), null, "Nonexisting item is null");
+ is(localStorage.getItem("key1"), null, "key1 removed");
+ is(localStorage.getItem("key2"), null, "key2 removed");
+ localStorage.removeItem("nonexisting"); // Just check there is no exception
+ localStorage.removeItem("key1"); // Just check there is no exception
+ localStorage.removeItem("key2"); // Just check there is no exception
+
+ localStorage.clear();
+ SimpleTest.finish();
+}
+
+SimpleTest.waitForExplicitFinish();
+
+</script>
+
+</head>
+
+<body onload="startTest();">
+
+</body>
+</html>
diff --git a/dom/tests/mochitest/localstorage/test_localStorageCookieSettings.html b/dom/tests/mochitest/localstorage/test_localStorageCookieSettings.html
new file mode 100644
index 0000000000..9860c67661
--- /dev/null
+++ b/dom/tests/mochitest/localstorage/test_localStorageCookieSettings.html
@@ -0,0 +1,75 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<title>localStorage cookies settings test</title>
+
+<script src="/tests/SimpleTest/SimpleTest.js"></script>
+<script type="text/javascript" src="interOriginTest.js"></script>
+<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+
+</head>
+<body>
+
+<script type="text/javascript">
+
+SimpleTest.waitForExplicitFinish();
+
+// Set cookies behavior to "always reject".
+SpecialPowers.pushPrefEnv({"set": [
+ ["network.cookie.cookieBehavior", 2],
+]}, test1);
+
+function test1() {
+ let w = window.open("windowProxy.html");
+ w.onload = _ => {
+ try {
+ w.localStorage.setItem("contentkey", "test-value");
+ ok(false, "Setting localStorageItem should throw a security exception");
+ }
+ catch(ex) {
+ is(ex.name, "SecurityError", "Got security exception");
+ }
+
+ w.close();
+
+ // Set cookies behavior to "reject 3rd party"
+ SpecialPowers.pushPrefEnv({"set": [["network.cookie.cookieBehavior", 1]], }, test2);
+ }
+}
+
+function test2() {
+ let w = window.open("windowProxy.html");
+ w.onload = _ => {
+ try {
+ w.localStorage.setItem("contentkey", "test-value");
+ ok(true, "Setting localStorageItem should not throw a security exception");
+ }
+ catch(ex) {
+ ok(false, "Setting localStorageItem should not throw a security exception");
+ }
+
+ var fileTest = (location.protocol + "//example.com" + location.pathname)
+ .replace("test_l", "frameL");
+
+ var myframe = w.document.createElement("iframe");
+ w.document.body.appendChild(myframe);
+ myframe.src = fileTest;
+
+ w.onmessage = function(e) {
+ switch (e.data.type || "") {
+ case "ok":
+ ok(e.data.what, e.data.msg);
+ break;
+ case "finish":
+ w.close();
+ SimpleTest.finish();
+ break;
+ default:
+ ok(false, "Invalid type.");
+ }
+ };
+ }
+}
+
+</script>
+</body>
+</html>
diff --git a/dom/tests/mochitest/localstorage/test_localStorageEnablePref.html b/dom/tests/mochitest/localstorage/test_localStorageEnablePref.html
new file mode 100644
index 0000000000..485f4e010a
--- /dev/null
+++ b/dom/tests/mochitest/localstorage/test_localStorageEnablePref.html
@@ -0,0 +1,65 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<title>localStorage enable preference test</title>
+
+<script src="/tests/SimpleTest/SimpleTest.js"></script>
+<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+
+<script type="text/javascript">
+
+SimpleTest.requestCompleteLog();
+
+function checkException(func, exc)
+{
+ var exceptionThrew = false;
+ try {
+ func();
+ }
+ catch (ex) {
+ exceptionThrew = true;
+ is(ex.name, exc, "Expected "+exc+" exception");
+ if (ex.name != exc) {
+ info("The exception which was thrown is: " + ex);
+ }
+ }
+ ok(exceptionThrew, "Exception "+exc+" threw");
+}
+
+var storage;
+function test1() {
+ is(typeof(window.localStorage), "object", "Storage is present");
+ storage = window.localStorage;
+
+ SpecialPowers.pushPrefEnv({"set": [["dom.storage.enabled", false]]}, test2);
+}
+
+function test2() {
+ is(window.localStorage, null, "Storage is null");
+
+ checkException(function() {storage.setItem("test", "value");}, "SecurityError");
+
+ SpecialPowers.pushPrefEnv({"set": [["dom.storage.enabled", true]]}, test3);
+}
+
+function test3() {
+ is(typeof(window.localStorage), "object", "Storage is present again");
+ storage.setItem("test", "value");
+ is(storage.getItem("test"), "value", "value can be set");
+ window.localStorage.clear();
+ SimpleTest.finish();
+}
+
+function doTest() {
+ SpecialPowers.pushPrefEnv({"set": [["dom.storage.enabled", true]]}, test1);
+}
+
+SimpleTest.waitForExplicitFinish();
+
+</script>
+
+</head>
+
+<body onload="doTest();">
+
+</body>
+</html>
diff --git a/dom/tests/mochitest/localstorage/test_localStorageFromChrome.xhtml b/dom/tests/mochitest/localstorage/test_localStorageFromChrome.xhtml
new file mode 100644
index 0000000000..fe7be443e9
--- /dev/null
+++ b/dom/tests/mochitest/localstorage/test_localStorageFromChrome.xhtml
@@ -0,0 +1,60 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<title>localStorage basic test</title>
+
+<script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css" />
+
+<script type="text/javascript">
+
+async function startTest()
+{
+ await SpecialPowers.pushPrefEnv({"set": [["dom.storage.client_validation", false]]});
+
+ var url = "http://example.com/tests/dom/tests/mochitest/localstorage/frameChromeSlave.html";
+ var ios = Components.classes["@mozilla.org/network/io-service;1"]
+ .getService(Components.interfaces.nsIIOService);
+ var ssm = Components.classes["@mozilla.org/scriptsecuritymanager;1"]
+ .getService(Components.interfaces.nsIScriptSecurityManager);
+ var dsm = Components.classes["@mozilla.org/dom/localStorage-manager;1"]
+ .getService(Components.interfaces.nsIDOMStorageManager);
+
+ var uri = ios.newURI(url);
+ var principal = ssm.createContentPrincipal(uri, {});
+ var storage = dsm.createStorage(window, principal, principal, "");
+
+ storage.setItem("chromekey", "chromevalue");
+
+ var aframe = document.getElementById("aframe");
+ aframe.onload = function()
+ {
+ is(storage.getItem("chromekey"), "chromevalue");
+ is(aframe.contentDocument.getElementById("data").innerHTML, "chromevalue");
+ SimpleTest.finish();
+ }
+ aframe.src = "http://example.com/tests/dom/tests/mochitest/localstorage/frameChromeSlave.html";
+
+ // Additionally check that we do not crash when we access the localStorage
+ // object in the owning chrome window (but we should throw). See bug 485396.
+ var exceptionCaught = false;
+ try {
+ localStorage;
+ }
+ catch (e) {
+ is(e.result, Components.results.NS_ERROR_NOT_AVAILABLE,
+ "Testing that we get the expected exception.");
+ exceptionCaught = true;
+ }
+ is(exceptionCaught, true, "Testing that an exception was thrown.");
+}
+
+SimpleTest.waitForExplicitFinish();
+
+</script>
+
+</head>
+
+<body onload="startTest();">
+ <iframe src="" id="aframe"></iframe>
+</body>
+</html>
diff --git a/dom/tests/mochitest/localstorage/test_localStorageKeyOrder.html b/dom/tests/mochitest/localstorage/test_localStorageKeyOrder.html
new file mode 100644
index 0000000000..a5dbb28b42
--- /dev/null
+++ b/dom/tests/mochitest/localstorage/test_localStorageKeyOrder.html
@@ -0,0 +1,73 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<title>localStorage key order test</title>
+
+<script src="/tests/SimpleTest/SimpleTest.js"></script>
+<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+
+<!--
+ Check we preserve order of keys in localStorage when
+ keys are just modified. When a new key is added or
+ a key is removed order is again unspecified.
+-->
+
+<script type="text/javascript">
+
+function startTest()
+{
+ try
+ {
+ var keyNames = new Array;
+ localStorage.a = "1";
+ localStorage.b = "2";
+ localStorage.c = "3";
+ localStorage.d = "4";
+ localStorage.e = "5";
+
+ is(localStorage.a, "1", "a = 1");
+ is(localStorage.b, "2", "b = 2");
+ is(localStorage.c, "3", "c = 3");
+ is(localStorage.d, "4", "d = 4");
+ is(localStorage.e, "5", "e = 5");
+ is(localStorage.length, 5, "length = 5");
+
+ for (var i = 0; i < localStorage.length; ++i)
+ keyNames[i] = localStorage.key(i);
+
+ localStorage.a = "10";
+ localStorage.b = "20";
+ localStorage.c = "30";
+ localStorage.d = "40";
+ localStorage.e = "50";
+
+ is(localStorage.a, "10", "a = 10");
+ is(localStorage.b, "20", "b = 20");
+ is(localStorage.c, "30", "c = 30");
+ is(localStorage.d, "40", "d = 40");
+ is(localStorage.e, "50", "e = 50");
+ is(localStorage.length, 5, "length = 5");
+
+ for (var i = 0; i < localStorage.length; ++i)
+ is(keyNames[i], localStorage.key(i), "key "+keyNames[i]+" on same index");
+
+ keyNamesStringify = "[\"" + keyNames.join("\",\"") + "\"]";
+ frame.location = "http://mochi.test:8888/tests/dom/tests/mochitest/localstorage/frameOrder.html?" +
+ keyNamesStringify;
+ }
+ catch (ex)
+ {
+ localStorage.clear();
+ throw ex;
+ }
+}
+
+SimpleTest.waitForExplicitFinish();
+
+</script>
+
+</head>
+
+<body onload="startTest();">
+ <iframe src="" name="frame"></frame>
+</body>
+</html>
diff --git a/dom/tests/mochitest/localstorage/test_localStorageOriginsDiff.html b/dom/tests/mochitest/localstorage/test_localStorageOriginsDiff.html
new file mode 100644
index 0000000000..96a93171ca
--- /dev/null
+++ b/dom/tests/mochitest/localstorage/test_localStorageOriginsDiff.html
@@ -0,0 +1,41 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<title>localStorage different origins</title>
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="interOriginTest2.js"></script>
+
+<!--
+ This test loads two frames from different
+ origins and checks that entries of localStorage
+ objects don't leak each between other.
+
+ The subsystem is based on postMessage and addEventListener
+ to send messages among different origins. The subsystem waits
+ for both frames be loaded and then alternately calls each frames'
+ doStep() function that on each call proceeds with a single step
+ of the test on its side. This way the subsystem alternate between
+ both frames until both sequences completely finish.
+-->
+
+<script type="text/javascript">
+
+function startTest()
+{
+ masterFrameOrigin = "http://example.org:80";
+ slaveFrameOrigin = "http://example.com:80";
+
+ masterFrame.location = masterFrameOrigin + framePath + "frameMasterNotEqual.html";
+ slaveFrame.location = slaveFrameOrigin + framePath + "frameSlaveNotEqual.html";
+}
+
+</script>
+
+</head>
+
+<body onload="startTest();">
+ <iframe src="" name="masterFrame"></iframe>
+ <iframe src="" name="slaveFrame"></iframe>
+</body>
+</html>
diff --git a/dom/tests/mochitest/localstorage/test_localStorageOriginsDomainDiffs.html b/dom/tests/mochitest/localstorage/test_localStorageOriginsDomainDiffs.html
new file mode 100644
index 0000000000..c1a4417727
--- /dev/null
+++ b/dom/tests/mochitest/localstorage/test_localStorageOriginsDomainDiffs.html
@@ -0,0 +1,41 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<title>localStorage different domains</title>
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="interOriginTest2.js"></script>
+
+<!--
+ This test loads two frames from different
+ origins and checks that entries of localStorage
+ objects don't leak each between other.
+
+ The subsystem is based on postMessage and addEventListener
+ to send messages among different origins. The subsystem waits
+ for both frames be loaded and then alternately calls each frames'
+ doStep() function that on each call proceeds with a single step
+ of the test on its side. This way the subsystem alternate between
+ both frames until both sequences completely finish.
+-->
+
+<script type="text/javascript">
+
+function startTest()
+{
+ masterFrameOrigin = "http://example.org:80";
+ slaveFrameOrigin = "http://test1.example.org:80";
+
+ masterFrame.location = masterFrameOrigin + framePath + "frameMasterNotEqual.html";
+ slaveFrame.location = slaveFrameOrigin + framePath + "frameSlaveNotEqual.html";
+}
+
+</script>
+
+</head>
+
+<body onload="startTest();">
+ <iframe src="" name="masterFrame"></iframe>
+ <iframe src="" name="slaveFrame"></iframe>
+</body>
+</html>
diff --git a/dom/tests/mochitest/localstorage/test_localStorageOriginsEquals.html b/dom/tests/mochitest/localstorage/test_localStorageOriginsEquals.html
new file mode 100644
index 0000000000..35cdd86b32
--- /dev/null
+++ b/dom/tests/mochitest/localstorage/test_localStorageOriginsEquals.html
@@ -0,0 +1,42 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<title>localStorage equal origins</title>
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="interOriginTest2.js"></script>
+
+<!--
+ This test loads two frames from equal
+ origins and checks that entries of localStorage
+ objects are kept up-to-date and synchronized
+ between both frames.
+
+ The subsystem is based on postMessage and addEventListener
+ to send messages among different origins. The subsystem waits
+ for both frames be loaded and then alternately calls each frames'
+ doStep() function that on each call proceeds with a single step
+ of the test on its side. This way the subsystem alternate between
+ both frames until both sequences completely finish.
+-->
+
+<script type="text/javascript">
+
+function startTest()
+{
+ masterFrameOrigin = "http://example.org:80";
+ slaveFrameOrigin = "http://example.org:80";
+
+ masterFrame.location = masterFrameOrigin + framePath + "frameMasterEqual.html";
+ slaveFrame.location = slaveFrameOrigin + framePath + "frameSlaveEqual.html";
+}
+
+</script>
+
+</head>
+
+<body onload="startTest();">
+ <iframe src="" name="masterFrame"></iframe>
+ <iframe src="" name="slaveFrame"></iframe>
+</body>
+</html>
diff --git a/dom/tests/mochitest/localstorage/test_localStorageOriginsPortDiffs.html b/dom/tests/mochitest/localstorage/test_localStorageOriginsPortDiffs.html
new file mode 100644
index 0000000000..d34e0dbcd1
--- /dev/null
+++ b/dom/tests/mochitest/localstorage/test_localStorageOriginsPortDiffs.html
@@ -0,0 +1,41 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<title>localStorage different port numbers</title>
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="interOriginTest2.js"></script>
+
+<!--
+ This test loads two frames from different
+ origins and checks that entries of localStorage
+ objects don't leak each between other.
+
+ The subsystem is based on postMessage and addEventListener
+ to send messages among different origins. The subsystem waits
+ for both frames be loaded and then alternately calls each frames'
+ doStep() function that on each call proceeds with a single step
+ of the test on its side. This way the subsystem alternate between
+ both frames until both sequences completely finish.
+-->
+
+<script type="text/javascript">
+
+function startTest()
+{
+ masterFrameOrigin = "http://example.org:80";
+ slaveFrameOrigin = "http://example.org:8000";
+
+ masterFrame.location = masterFrameOrigin + framePath + "frameMasterNotEqual.html";
+ slaveFrame.location = slaveFrameOrigin + framePath + "frameSlaveNotEqual.html";
+}
+
+</script>
+
+</head>
+
+<body onload="startTest();">
+ <iframe src="" name="masterFrame"></iframe>
+ <iframe src="" name="slaveFrame"></iframe>
+</body>
+</html>
diff --git a/dom/tests/mochitest/localstorage/test_localStorageOriginsSchemaDiffs.html b/dom/tests/mochitest/localstorage/test_localStorageOriginsSchemaDiffs.html
new file mode 100644
index 0000000000..57e4fb5ab3
--- /dev/null
+++ b/dom/tests/mochitest/localstorage/test_localStorageOriginsSchemaDiffs.html
@@ -0,0 +1,41 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<title>localStorage different domains</title>
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="interOriginTest2.js"></script>
+
+<!--
+ This test loads two frames from different
+ origins and checks that entries of localStorage
+ objects don't leak each between other.
+
+ The subsystem is based on postMessage and addEventListener
+ to send messages among different origins. The subsystem waits
+ for both frames be loaded and then alternately calls each frames'
+ doStep() function that on each call proceeds with a single step
+ of the test on its side. This way the subsystem alternate between
+ both frames until both sequences completely finish.
+-->
+
+<script type="text/javascript">
+
+function startTest()
+{
+ masterFrameOrigin = "http://example.com";
+ slaveFrameOrigin = "https://example.com";
+
+ masterFrame.location = masterFrameOrigin + framePath + "frameMasterNotEqual.html";
+ slaveFrame.location = slaveFrameOrigin + framePath + "frameSlaveNotEqual.html";
+}
+
+</script>
+
+</head>
+
+<body onload="startTest();">
+ <iframe src="" name="masterFrame"></iframe>
+ <iframe src="" name="slaveFrame"></iframe>
+</body>
+</html>
diff --git a/dom/tests/mochitest/localstorage/test_localStorageQuota.html b/dom/tests/mochitest/localstorage/test_localStorageQuota.html
new file mode 100644
index 0000000000..a26252b313
--- /dev/null
+++ b/dom/tests/mochitest/localstorage/test_localStorageQuota.html
@@ -0,0 +1,136 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<title>localStorage and DOM quota test</title>
+
+<script src="/tests/SimpleTest/SimpleTest.js"></script>
+<script type="text/javascript" src="interOriginTest.js"></script>
+<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+
+<script type="text/javascript">
+//Note: this test is currently giving failures when running standalone, see bug 914865
+
+var currentTest = 1;
+
+function doNextTest()
+{
+ slave = frame;
+
+ switch (currentTest)
+ {
+ case 1:
+ if (SpecialPowers.Services.domStorageManager.nextGenLocalStorageEnabled) {
+ slaveOrigin = "http://test1.example.com";
+ } else {
+ slaveOrigin = "http://example.com";
+ }
+ slave.location = slaveOrigin + slavePath + "frameQuota.html?add&A&success";
+ break;
+
+ // Now set another key with length 500 bytes, i.e. allocate 501 bytes
+ case 2:
+ slaveOrigin = "http://test1.example.com";
+ slave.location = slaveOrigin + slavePath + "frameQuota.html?add&B&success";
+ break;
+
+ // Try to set the same key value again to check we don't fail
+ // even 1002 bytes has already been exhausted from the quota
+ // We just change the value of an existing key.
+ case 3:
+ slaveOrigin = "http://test1.example.com";
+ slave.location = slaveOrigin + slavePath + "frameQuota.html?add&B&success";
+ break;
+
+ // Try to set the same key to a larger value that would lead to
+ // quota reach and check that the value is still the old one
+ case 4:
+ slaveOrigin = "http://test1.example.com";
+ slave.location = slaveOrigin + slavePath + "frameQuota.html?add2&B&failure";
+ break;
+
+ // Try to set a new 500 bytes key and check we fail because we are over the
+ // quota.
+ case 5:
+ if (SpecialPowers.Services.domStorageManager.nextGenLocalStorageEnabled) {
+ slaveOrigin = "http://test1.example.com";
+ } else if (SpecialPowers.Services.appinfo.fissionAutostart){
+ // Fission makes the "https://test2.example.com" run in the different
+ // process with the other two and Legacy LS has issues with usage
+ // synchronization within processes, see Bug 1683299 for more details.
+ slaveOrigin = "http://test2.example.com";
+ } else {
+ slaveOrigin = "https://test2.example.com";
+ }
+ slave.location = slaveOrigin + slavePath + "frameQuota.html?add&C&failure";
+ break;
+
+ // Remove the second key, it must not fail. This should release the
+ // allocated space of the quota assigned to test1.example.com.
+ case 6:
+ slaveOrigin = "http://test1.example.com";
+ slave.location = slaveOrigin + slavePath + "frameQuota.html?remove&B&success";
+ break;
+
+ // Now try again to set 500 bytes key, it must succeed.
+ case 7:
+ if (SpecialPowers.Services.domStorageManager.nextGenLocalStorageEnabled) {
+ slaveOrigin = "http://test1.example.com";
+ } else if (SpecialPowers.Services.appinfo.fissionAutostart){
+ slaveOrigin = "http://test2.example.com";
+ } else {
+ slaveOrigin = "https://test2.example.com";
+ }
+ slave.location = slaveOrigin + slavePath + "frameQuota.html?add&C&success";
+ break;
+
+ case 8:
+ if (SpecialPowers.Services.domStorageManager.nextGenLocalStorageEnabled) {
+ SimpleTest.executeSoon(doNextTest);
+ } else {
+ // Do a clean up...
+ slaveOrigin = "http://example.com";
+ slave.location = slaveOrigin + slavePath + "frameQuota.html?clear";
+ }
+ break;
+
+ case 9:
+ // Do a clean up...
+ slaveOrigin = "http://test1.example.com";
+ slave.location = slaveOrigin + slavePath + "frameQuota.html?clear";
+ break;
+
+ case 10:
+ if (SpecialPowers.Services.domStorageManager.nextGenLocalStorageEnabled) {
+ SimpleTest.executeSoon(doNextTest);
+ } else {
+ // Do a clean up...
+ slaveOrigin = "https://test2.example.com";
+ slave.location = slaveOrigin + slavePath + "frameQuota.html?clear";
+ }
+ break;
+
+ default: // end
+ SimpleTest.finish();
+ }
+
+ ++currentTest;
+}
+
+function doStep()
+{
+}
+
+SimpleTest.waitForExplicitFinish();
+
+function startTest() {
+ // Initialy setup the quota to testing value of 1024B and
+ // set a 500 bytes key with name length 1 (allocate 501 bytes)
+ SpecialPowers.pushPrefEnv({"set": [["dom.storage.default_quota", 1], ["dom.storage.default_site_quota", 1], ["security.mixed_content.block_display_content", false], ["security.mixed_content.block_active_content", false]]}, doNextTest);
+}
+</script>
+
+</head>
+
+<body onload="startTest();">
+ <iframe src="" name="frame"></iframe>
+</body>
+</html>
diff --git a/dom/tests/mochitest/localstorage/test_localStorageQuotaPrivateBrowsing_perwindowpb.html b/dom/tests/mochitest/localstorage/test_localStorageQuotaPrivateBrowsing_perwindowpb.html
new file mode 100644
index 0000000000..ab04360821
--- /dev/null
+++ b/dom/tests/mochitest/localstorage/test_localStorageQuotaPrivateBrowsing_perwindowpb.html
@@ -0,0 +1,189 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<title>localStorage and DOM quota test</title>
+
+<script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"?>
+
+<script type="text/javascript">
+SimpleTest.waitForExplicitFinish();
+
+const CONTENT_PAGE = "http://mochi.test:8888/chrome/dom/tests/mochitest/localstorage/page_blank.html";
+const slavePath = "/chrome/dom/tests/mochitest/localstorage/";
+var currentTest = 1;
+var quota = Services.prefs.getIntPref("dom.storage.default_quota", 5 * 1024);
+var siteQuota = Services.prefs.getIntPref("dom.storage.default_site_quota", 25 * 1024);
+Services.prefs.setIntPref("browser.startup.page", 0);
+Services.prefs.setIntPref("dom.storage.default_quota", 1);
+Services.prefs.setIntPref("dom.storage.default_site_quota", 1);
+
+var slaveLoadsPending = 1;
+var slaveOrigin = "";
+var slave = null;
+var failureRegExp = new RegExp("^FAILURE");
+
+function startTest() {
+ testOnWindow(true, function(aWindow) {
+ info("Private window loaded");
+ var frame = aWindow.content.document.createElement("iframe");
+ aWindow.content.document.body.appendChild(frame);
+ aWindow.content.addEventListener("message", function(aEvent) {
+ onMessageReceived(aEvent, aWindow)
+ });
+ slave = aWindow.content.frames[0];
+
+ SimpleTest.waitForFocus(() => doNextTest(aWindow), aWindow);
+ });
+}
+
+function doNextTest(aWindow) {
+ info("Running test: " + currentTest);
+ switch (currentTest) {
+ // Initialy setup the quota to testing value of 1024B and
+ // set a 500 bytes key with name length 1 (allocate 501 bytes)
+ case 1:
+ if (SpecialPowers.Services.domStorageManager.nextGenLocalStorageEnabled) {
+ slaveOrigin = "http://test1.example.com";
+ } else {
+ slaveOrigin = "http://example.com";
+ }
+ slave.location = slaveOrigin + slavePath + "frameQuota.html?add&A&success";
+ break;
+
+ // Now set another key with length 500 bytes, i.e. allocate 501 bytes
+ case 2:
+ slaveOrigin = "http://test1.example.com";
+ slave.location = slaveOrigin + slavePath + "frameQuota.html?add&B&success";
+ break;
+
+ // Try to set the same key value again to check we don't fail
+ // even 1002 bytes has already been exhausted from the quota
+ // We just change the value of an existing key.
+ case 3:
+ slaveOrigin = "http://test1.example.com";
+ slave.location = slaveOrigin + slavePath + "frameQuota.html?add&B&success";
+ break;
+
+ // Try to set the same key to a larger value that would lead to
+ // quota reach and check that the value is still the old one
+ case 4:
+ slaveOrigin = "http://test1.example.com";
+ slave.location = slaveOrigin + slavePath + "frameQuota.html?add2&B&failure";
+ break;
+
+ // Try to set a new 500 bytes key and check we fail because we are over the
+ // quota.
+ case 5:
+ if (SpecialPowers.Services.domStorageManager.nextGenLocalStorageEnabled) {
+ slaveOrigin = "http://test1.example.com";
+ } else {
+ slaveOrigin = "https://test2.example.com";
+ }
+ slave.location = slaveOrigin + slavePath + "frameQuota.html?add&C&failure";
+ break;
+
+ // Remove the second key, it must not fail. This should release the
+ // allocated space of the quota assigned to test1.example.com.
+ case 6:
+ slaveOrigin = "http://test1.example.com";
+ slave.location = slaveOrigin + slavePath + "frameQuota.html?remove&B&success";
+ break;
+
+ // Now try again to set 500 bytes key, it must succeed.
+ case 7:
+ if (SpecialPowers.Services.domStorageManager.nextGenLocalStorageEnabled) {
+ slaveOrigin = "http://test1.example.com";
+ } else {
+ slaveOrigin = "https://test2.example.com";
+ }
+ slave.location = slaveOrigin + slavePath + "frameQuota.html?add&C&success";
+ break;
+
+ case 8:
+ if (SpecialPowers.Services.domStorageManager.nextGenLocalStorageEnabled) {
+ SimpleTest.executeSoon(() => doNextTest(aWindow));
+ } else {
+ // Do a clean up...
+ slaveOrigin = "http://example.com";
+ slave.location = slaveOrigin + slavePath + "frameQuota.html?clear";
+ }
+ break;
+
+ case 9:
+ // Do a clean up...
+ slaveOrigin = "http://test1.example.com";
+ slave.location = slaveOrigin + slavePath + "frameQuota.html?clear";
+ break;
+
+ case 10:
+ if (SpecialPowers.Services.domStorageManager.nextGenLocalStorageEnabled) {
+ SimpleTest.executeSoon(() => doNextTest(aWindow));
+ } else {
+ // Do a clean up...
+ slaveOrigin = "https://test2.example.com";
+ slave.location = slaveOrigin + slavePath + "frameQuota.html?clear";
+ }
+ break;
+
+ default:
+ Services.prefs.clearUserPref("browser.startup.page")
+ Services.prefs.setIntPref("dom.storage.default_quota", quota);
+ Services.prefs.setIntPref("dom.storage.default_site_quota", siteQuota);
+ aWindow.close();
+ SimpleTest.finish();
+ }
+
+ ++currentTest;
+}
+
+function onMessageReceived(event, aWindow) {
+ info("Message received: " + event.data);
+ switch (event.data) {
+ // Indication of the frame onload event
+ case "frame loaded":
+ if (--slaveLoadsPending)
+ break;
+ // Indication of successfully finished step of a test
+ // Just fall through...
+ case "perf":
+ // postMessage should send to the slaveOrigin. However with the addition of private
+ // browsing flags in origin attributes this will cause postMessage to fail. The origin of this
+ // window has false privatebrowsing, while the recipient is in a private window.
+ // To fix this issue and preserve the integrity of the test a * is passed to get around origin equality.
+ slave.postMessage("step", "*");
+ break;
+ // Indication of all test parts finish (from any of the frames)
+ case "done":
+ aWindow.content.localStorage.clear();
+ slaveLoadsPending = 1;
+ doNextTest(aWindow);
+ break;
+ // Any other message indicates error or succes message of a test
+ default:
+ SimpleTest.ok(!event.data.match(failureRegExp), event.data);
+ break;
+ }
+}
+
+function whenDelayedStartupFinished(aCallback) {
+ Services.obs.addObserver(function observer(aSubject, aTopic) {
+ Services.obs.removeObserver(observer, aTopic);
+
+ aSubject.addEventListener("DOMContentLoaded", function() {
+ SimpleTest.executeSoon(function() { aCallback(aSubject); });
+ }, {capture: true, once: true});
+ }, "browser-delayed-startup-finished");
+}
+
+function testOnWindow(aIsPrivate, callback) {
+ var mainWindow = window.browsingContext.topChromeWindow;
+
+ mainWindow.openWebLinkIn(CONTENT_PAGE, "window", {
+ private: aIsPrivate });
+ whenDelayedStartupFinished(callback);
+};
+</script>
+</head>
+<body onload="startTest();">
+</body>
+</html>
diff --git a/dom/tests/mochitest/localstorage/test_localStorageQuotaSessionOnly.html b/dom/tests/mochitest/localstorage/test_localStorageQuotaSessionOnly.html
new file mode 100644
index 0000000000..1d32776907
--- /dev/null
+++ b/dom/tests/mochitest/localstorage/test_localStorageQuotaSessionOnly.html
@@ -0,0 +1,134 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<title>localStorage and DOM quota test</title>
+
+<script src="/tests/SimpleTest/SimpleTest.js"></script>
+<script type="text/javascript" src="interOriginTest.js"></script>
+<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+
+<script type="text/javascript">
+
+var currentTest = 1;
+
+function doNextTest()
+{
+ slave = frame;
+
+ switch (currentTest)
+ {
+ case 1:
+ slaveOrigin = "http://example.com";
+ slave.location = slaveOrigin + slavePath + "frameQuotaSessionOnly.html?add&A&success";
+ break;
+
+ // In subdomain now set another key with length 500 bytes, i.e.
+ // allocate 501 bytes
+ case 2:
+ slaveOrigin = "http://test1.example.com";
+ slave.location = slaveOrigin + slavePath + "frameQuotaSessionOnly.html?add&B&success";
+ break;
+
+ // Try to set the same key value again to check we don't fail
+ // even 1002 bytes has already been exhausted from the quota
+ // We just change the value of an existing key.
+ case 3:
+ slaveOrigin = "http://test1.example.com";
+ slave.location = slaveOrigin + slavePath + "frameQuotaSessionOnly.html?add&B&success";
+ break;
+
+ // Try to set the same key to a larger value that would lead to
+ // quota reach and check that the value is still the old one
+ case 4:
+ slaveOrigin = "http://test1.example.com";
+ slave.location = slaveOrigin + slavePath + "frameQuotaSessionOnly.html?add2&B&failure";
+ break;
+
+ // In a different subdomain try to set a new 500 bytes key
+ // and check we fail because we are over the quota
+ case 5:
+ slaveOrigin = "https://test2.example.com";
+ slave.location = slaveOrigin + slavePath + "frameQuotaSessionOnly.html?add&C&failure";
+ break;
+
+ // Remove from the second subdomain the second key, it must not fail
+ // This should release the allocated space of the quota assigned to
+ // example.com.
+ case 6:
+ slaveOrigin = "http://test1.example.com";
+ slave.location = slaveOrigin + slavePath + "frameQuotaSessionOnly.html?remove&B&success";
+ break;
+
+ // Now try again to set 500 bytes key, it must succeed.
+ case 7:
+ slaveOrigin = "https://test2.example.com";
+ slave.location = slaveOrigin + slavePath + "frameQuotaSessionOnly.html?add&C&success";
+ break;
+
+ case 8:
+ // Do a clean up...
+ slaveOrigin = "http://example.com";
+ slave.location = slaveOrigin + slavePath + "frameQuotaSessionOnly.html?clear";
+ break;
+
+ case 9:
+ // Do a clean up...
+ slaveOrigin = "http://test1.example.com";
+ slave.location = slaveOrigin + slavePath + "frameQuotaSessionOnly.html?clear";
+ break;
+
+ case 10:
+ // Do a clean up...
+ slaveOrigin = "https://test2.example.com";
+ slave.location = slaveOrigin + slavePath + "frameQuotaSessionOnly.html?clear";
+ break;
+
+ default:
+ SimpleTest.finish();
+ }
+
+ ++currentTest;
+}
+
+function doStep()
+{
+}
+
+SimpleTest.waitForExplicitFinish();
+
+function startTest() {
+ if (SpecialPowers.Services.domStorageManager.nextGenLocalStorageEnabled) {
+ ok(true, "Test ignored when the next gen local storage is enabled.");
+ SimpleTest.finish();
+ return;
+ }
+
+ SpecialPowers.pushPermissions([
+ {
+ type: "cookie",
+ allow: SpecialPowers.Ci.nsICookiePermission.ACCESS_SESSION,
+ context: "http://example.com",
+ },
+ {
+ type: "cookie",
+ allow: SpecialPowers.Ci.nsICookiePermission.ACCESS_SESSION,
+ context: "http://test1.example.com",
+ },
+ {
+ type: "cookie",
+ allow: SpecialPowers.Ci.nsICookiePermission.ACCESS_SESSION,
+ context: "https://test2.example.com",
+ },
+ ], function() {
+ // Initialy setup the quota to testing value of 1024B and
+ // set a 500 bytes key with name length 1 (allocate 501 bytes)
+ SpecialPowers.pushPrefEnv({"set": [["dom.storage.default_quota", 1], ["dom.storage.default_site_quota", 1], ["security.mixed_content.block_display_content", false], ["security.mixed_content.block_active_content", false]]}, doNextTest);
+ });
+}
+</script>
+
+</head>
+
+<body onload="startTest();">
+ <iframe src="" name="frame"></iframe>
+</body>
+</html>
diff --git a/dom/tests/mochitest/localstorage/test_localStorageQuotaSessionOnly2.html b/dom/tests/mochitest/localstorage/test_localStorageQuotaSessionOnly2.html
new file mode 100644
index 0000000000..156ff02bf6
--- /dev/null
+++ b/dom/tests/mochitest/localstorage/test_localStorageQuotaSessionOnly2.html
@@ -0,0 +1,98 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<title>localStorage and DOM quota test</title>
+
+<script src="/tests/SimpleTest/SimpleTest.js"></script>
+<script type="text/javascript" src="interOriginTest.js"></script>
+<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+
+<script type="text/javascript">
+
+var currentTest = 1;
+
+function doNextTest()
+{
+ slave = frame;
+
+ switch (currentTest)
+ {
+ case 1:
+ slaveOrigin = "http://example.com";
+ slave.location = slaveOrigin + slavePath + "frameQuotaSessionOnly.html?add&A&success";
+ break;
+
+ // In subdomain now set another key with length 500 bytes, i.e.
+ // allocate 501 bytes
+ case 2:
+ slaveOrigin = "http://example.com";
+ slave.location = slaveOrigin + slavePath + "frameQuotaSessionOnly.html?add&B&success";
+ break;
+
+ // Try to set the same key value again to check we don't fail
+ // even 1002 bytes has already been exhausted from the quota
+ // We just change the value of an existing key.
+ case 3:
+ slaveOrigin = "http://example.com";
+ slave.location = slaveOrigin + slavePath + "frameQuotaSessionOnly.html?add&B&success";
+ break;
+
+ // Try to set the same key to a larger value that would lead to
+ // quota reach and check that the value is still the old one
+ case 4:
+ slaveOrigin = "http://example.com";
+ slave.location = slaveOrigin + slavePath + "frameQuotaSessionOnly.html?add2&B&failure";
+ break;
+
+ // Try to set a new 500 bytes key
+ // and check we fail because we are over the quota
+ case 5:
+ slaveOrigin = "https://example.com";
+ slave.location = slaveOrigin + slavePath + "frameQuotaSessionOnly.html?add&C&failure";
+ break;
+
+ // Remove the key inherited from the non-session-only database
+ case 6:
+ slaveOrigin = "http://example.com";
+ slave.location = slaveOrigin + slavePath + "frameQuotaSessionOnly.html?remove&A&success";
+ break;
+
+ // Now try again to set 500 bytes key, it must succeed.
+ case 7:
+ slaveOrigin = "https://example.com";
+ slave.location = slaveOrigin + slavePath + "frameQuotaSessionOnly.html?add&C&success";
+ break;
+
+ case 8:
+ // Do a clean up...
+ slaveOrigin = "http://example.com";
+ slave.location = slaveOrigin + slavePath + "frameQuotaSessionOnly.html?clear";
+ break;
+
+ default:
+ SimpleTest.finish();
+ }
+
+ ++currentTest;
+}
+
+function doStep()
+{
+}
+
+SimpleTest.waitForExplicitFinish();
+
+function startTest() {
+ // Initialy setup the quota to testing value of 1024B and
+ // set a 500 bytes key with name length 1 (allocate 501 bytes)
+ SpecialPowers.pushPrefEnv({"set": [["dom.storage.default_quota", 1], ["dom.storage.default_site_quota", 1], ["security.mixed_content.block_display_content", false], ["security.mixed_content.block_active_content", false]]}, function() {
+ SpecialPowers.pushPermissions([{'type': 'cookie', 'allow': SpecialPowers.Ci.nsICookiePermission.ACCESS_SESSION, 'context': document}], doNextTest);
+ });
+}
+</script>
+
+</head>
+
+<body onload="startTest();">
+ <iframe src="" name="frame"></iframe>
+</body>
+</html>
diff --git a/dom/tests/mochitest/localstorage/test_localStorageReplace.html b/dom/tests/mochitest/localstorage/test_localStorageReplace.html
new file mode 100644
index 0000000000..b80c35dbc5
--- /dev/null
+++ b/dom/tests/mochitest/localstorage/test_localStorageReplace.html
@@ -0,0 +1,80 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<title>localStorage replace test</title>
+
+<!--
+ This test checks that localStorage object doesn't leak
+ in a window that changes its location. We do this by switching
+ frame location inside of this window and then by changing location
+ of a top level window.
+-->
+
+<script src="/tests/SimpleTest/SimpleTest.js"></script>
+<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+
+<script type="text/javascript">
+
+var shell;
+var shellType;
+var failureRegExp = new RegExp("^FAILURE");
+
+window.addEventListener("message", onMessageReceived);
+
+function onMessageReceived(event)
+{
+ switch (event.data)
+ {
+ case "init_done":
+ // This is frame with different origin in the same browsing context
+ // as the first frame adding data to localStorage of the first origin.
+ shell.location = "http://example.com:80/tests/dom/tests/mochitest/localstorage/frameReplace.html?check&" + shellType;
+ break;
+
+ case "check_done":
+ // Clean the localStorage of the first origin.
+ shell.location = "http://example.org:80/tests/dom/tests/mochitest/localstorage/frameReplace.html?clean&" + shellType;
+ break;
+
+ case "clean_done":
+ switch (shellType)
+ {
+ case "frame":
+ // We finished testing in a frame
+ // proceed with test in a separate window
+ shellType = "window";
+ shell = window.open("http://example.org:80/tests/dom/tests/mochitest/localstorage/frameReplace.html?init&" + shellType);
+ break;
+
+ case "window":
+ shell.close();
+ window.setTimeout(function() {SimpleTest.finish();}, 0);
+ break;
+ }
+ break;
+
+ default:
+ SimpleTest.ok(!event.data.match(failureRegExp), event.data);
+ break;
+ }
+}
+
+function startTest() {
+ SpecialPowers.pushPrefEnv({"set": [["security.mixed_content.block_display_content", false], ["security.mixed_content.block_active_content", false]]}, test1);
+}
+
+function test1() {
+ shellType = "frame";
+ shell = frame;
+ shell.location = "http://example.org:80/tests/dom/tests/mochitest/localstorage/frameReplace.html?init&" + shellType;
+}
+
+SimpleTest.waitForExplicitFinish();
+
+</script>
+
+</head>
+
+<body onload="startTest();">
+ <iframe src="" name="frame"></iframe>
+</body>
+</html>
diff --git a/dom/tests/mochitest/localstorage/test_storageConstructor.html b/dom/tests/mochitest/localstorage/test_storageConstructor.html
new file mode 100644
index 0000000000..e0aa4e11dc
--- /dev/null
+++ b/dom/tests/mochitest/localstorage/test_storageConstructor.html
@@ -0,0 +1,35 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<title>Storage interface</title>
+
+<script src="/tests/SimpleTest/SimpleTest.js"></script>
+<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+
+<script type="text/javascript">
+
+function startTest()
+{
+ var functionCalled = false;
+ is(localStorage instanceof Storage, true, "localStorage is instance of Storage");
+ Storage.prototype.exists = function(key) {
+ functionCalled = true;
+ return this.getItem(key) != null;
+ }
+ localStorage.setItem("test_prototype", "value");
+ is(functionCalled, false, "Overridden function not called");
+ is(localStorage.exists("test_prototype"), true, "Prototype overridden");
+ is(functionCalled, true, "Overridden function called");
+ localStorage.clear();
+
+ SimpleTest.finish();
+}
+
+SimpleTest.waitForExplicitFinish();
+
+</script>
+
+</head>
+
+<body onload="startTest();">
+</body>
+</html>
diff --git a/dom/tests/mochitest/localstorage/windowProxy.html b/dom/tests/mochitest/localstorage/windowProxy.html
new file mode 100644
index 0000000000..39ba8eab0f
--- /dev/null
+++ b/dom/tests/mochitest/localstorage/windowProxy.html
@@ -0,0 +1,3 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+<body></body>
+</html>