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/frameChromeSlave.html9
-rw-r--r--dom/tests/mochitest/localstorage/frameKeySync.html51
-rw-r--r--dom/tests/mochitest/localstorage/frameLocalStorageCookieSettings.html20
-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.html105
-rw-r--r--dom/tests/mochitest/localstorage/frameQuotaSessionOnly.html111
-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.js57
-rw-r--r--dom/tests/mochitest/localstorage/interOriginTest.js42
-rw-r--r--dom/tests/mochitest/localstorage/interOriginTest2.js53
-rw-r--r--dom/tests/mochitest/localstorage/localStorageCommon.js45
-rw-r--r--dom/tests/mochitest/localstorage/mochitest.ini52
-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.html166
-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.html42
-rw-r--r--dom/tests/mochitest/localstorage/test_cookieSession.html132
-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.html263
-rw-r--r--dom/tests/mochitest/localstorage/test_localStorageBaseSessionOnly.html205
-rw-r--r--dom/tests/mochitest/localstorage/test_localStorageCookieSettings.html59
-rw-r--r--dom/tests/mochitest/localstorage/test_localStorageEnablePref.html65
-rw-r--r--dom/tests/mochitest/localstorage/test_localStorageFromChrome.xhtml58
-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.html111
-rw-r--r--dom/tests/mochitest/localstorage/test_localStorageQuotaPrivateBrowsing_perwindowpb.html192
-rw-r--r--dom/tests/mochitest/localstorage/test_localStorageQuotaSessionOnly.html112
-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_localStorageSessionPrefOverride.html54
-rw-r--r--dom/tests/mochitest/localstorage/test_lowDeviceStorage.html76
-rw-r--r--dom/tests/mochitest/localstorage/test_storageConstructor.html35
47 files changed, 3377 insertions, 0 deletions
diff --git a/dom/tests/mochitest/localstorage/chrome.ini b/dom/tests/mochitest/localstorage/chrome.ini
new file mode 100644
index 000000000..6cc5562c0
--- /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/frameChromeSlave.html b/dom/tests/mochitest/localstorage/frameChromeSlave.html
new file mode 100644
index 000000000..fd87702e9
--- /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 000000000..4bc4794e6
--- /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 000000000..de42e6bb9
--- /dev/null
+++ b/dom/tests/mochitest/localstorage/frameLocalStorageCookieSettings.html
@@ -0,0 +1,20 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<title>localStorage cookies settings test</title>
+
+<script type="text/javascript" src="interOriginFrame.js"></script>
+
+</head>
+<body>
+<script type="text/javascript">
+ try {
+ localStorage.setItem("contentkey", "test-value");
+ ok(false, "Setting localStorageItem should throw a security exception");
+ } catch(ex) {
+ is(ex.name, "SecurityError");
+ }
+
+ finishTest();
+</script>
+</body>
+</html>
diff --git a/dom/tests/mochitest/localstorage/frameLocalStorageSessionOnly.html b/dom/tests/mochitest/localstorage/frameLocalStorageSessionOnly.html
new file mode 100644
index 000000000..f6c7f0291
--- /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 000000000..4d83c4fef
--- /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 000000000..fef476bed
--- /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 000000000..3b3f0ebef
--- /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 000000000..d3e32ad71
--- /dev/null
+++ b/dom/tests/mochitest/localstorage/frameQuota.html
@@ -0,0 +1,105 @@
+<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_REACHED = 2152924150;
+
+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;
+
+ case "checkclean":
+ is(localStorage.getItem(keyName), null, "Key "+keyName+" not present");
+ break;
+
+ case "checknotclean":
+ is(localStorage.getItem(keyName), "12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890", "Key "+keyName+" is present");
+ 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_REACHED exception
+ checkException(function() {
+ localStorage.setItem(keyName, "12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890");
+ }, DOM_QUOTA_REACHED);
+ 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_REACHED);
+ 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 000000000..a6f69b176
--- /dev/null
+++ b/dom/tests/mochitest/localstorage/frameQuotaSessionOnly.html
@@ -0,0 +1,111 @@
+<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_REACHED = 2152924150;
+
+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;
+
+ case "checkclean":
+ is(localStorage.getItem(keyName), null, "Key "+keyName+" not present");
+ break;
+
+ case "checknotclean":
+ is(localStorage.getItem(keyName), "12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890", "Key "+keyName+" is present");
+ 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_REACHED exception
+ checkException(function() {
+ localStorage.setItem(keyName, "12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890");
+ }, DOM_QUOTA_REACHED);
+ 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_REACHED);
+ 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() {
+ SpecialPowers.pushPermissions([{'type': 'cookie', 'allow': SpecialPowers.Ci.nsICookiePermission.ACCESS_SESSION, 'context': document}], function() {
+ 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 000000000..145bfe8fc
--- /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 000000000..b64b8de10
--- /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 000000000..9daf9e9f7
--- /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 000000000..185ef8858
--- /dev/null
+++ b/dom/tests/mochitest/localstorage/interOriginFrame.js
@@ -0,0 +1,57 @@
+function postMsg(message)
+{
+ parent.postMessage(message, "http://mochi.test:8888");
+}
+
+window.addEventListener("message", onMessageReceived, false);
+
+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 000000000..dcfac783a
--- /dev/null
+++ b/dom/tests/mochitest/localstorage/interOriginTest.js
@@ -0,0 +1,42 @@
+var slaveLoadsPending = 1;
+
+var slaveOrigin = "";
+var slave = null;
+
+var failureRegExp = new RegExp("^FAILURE");
+const slavePath = "/tests/dom/tests/mochitest/localstorage/";
+
+window.addEventListener("message", onMessageReceived, false);
+
+function onMessageReceived(event)
+{
+ switch (event.data)
+ {
+ // Indication of the frame onload event
+ case "frame loaded":
+ if (--slaveLoadsPending)
+ break;
+
+ // Just fall through...
+
+ // Indication of successfully finished step of a test
+ 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 000000000..e3f3c8771
--- /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, false);
+
+function onMessageReceived(event)
+{
+ switch (event.data)
+ {
+ // Indication of the frame onload event
+ case "frame loaded":
+ if (--frameLoadsPending)
+ break;
+
+ // Just fall through...
+
+ // Indication of successfully finished step of a test
+ 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 000000000..5ca414067
--- /dev/null
+++ b/dom/tests/mochitest/localstorage/localStorageCommon.js
@@ -0,0 +1,45 @@
+function localStorageFlush(cb)
+{
+ var ob = {
+ observe : function(sub, top, dat)
+ {
+ os().removeObserver(ob, "domstorage-test-flushed");
+ cb();
+ }
+ };
+ os().addObserver(ob, "domstorage-test-flushed", false);
+ notify("domstorage-test-flush-force");
+}
+
+function localStorageReload()
+{
+ notify("domstorage-test-reload");
+}
+
+function localStorageFlushAndReload(cb)
+{
+ localStorageFlush(function() {
+ localStorageReload();
+ cb();
+ });
+}
+
+function localStorageClearAll()
+{
+ os().notifyObservers(null, "cookie-changed", "cleared");
+}
+
+function localStorageClearDomain(domain)
+{
+ os().notifyObservers(null, "browser:purge-domain-data", domain);
+}
+
+function os()
+{
+ return SpecialPowers.Services.obs;
+}
+
+function notify(top)
+{
+ os().notifyObservers(null, top, null);
+}
diff --git a/dom/tests/mochitest/localstorage/mochitest.ini b/dom/tests/mochitest/localstorage/mochitest.ini
new file mode 100644
index 000000000..5242bf9b1
--- /dev/null
+++ b/dom/tests/mochitest/localstorage/mochitest.ini
@@ -0,0 +1,52 @@
+[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
+
+[test_brokenUTF-16.html]
+[test_bug600307-DBOps.html]
+[test_bug746272-1.html]
+[test_bug746272-2.html]
+skip-if = os == "android" # bug 962029
+[test_cookieBlock.html]
+[test_cookieSession.html]
+[test_embededNulls.html]
+[test_keySync.html]
+[test_localStorageBase.html]
+skip-if = e10s
+[test_localStorageBaseSessionOnly.html]
+[test_localStorageCookieSettings.html]
+[test_localStorageEnablePref.html]
+[test_localStorageKeyOrder.html]
+[test_localStorageOriginsDiff.html]
+[test_localStorageOriginsDomainDiffs.html]
+[test_localStorageOriginsEquals.html]
+skip-if = toolkit == 'android'
+[test_localStorageOriginsPortDiffs.html]
+[test_localStorageOriginsSchemaDiffs.html]
+skip-if = toolkit == 'android' #TIMED_OUT
+[test_localStorageQuota.html]
+skip-if = toolkit == 'android' #TIMED_OUT
+[test_localStorageQuotaSessionOnly.html]
+skip-if = toolkit == 'android' #TIMED_OUT
+[test_localStorageQuotaSessionOnly2.html]
+skip-if = toolkit == 'android' #TIMED_OUT
+[test_localStorageReplace.html]
+skip-if = toolkit == 'android'
+[test_lowDeviceStorage.html]
+[test_storageConstructor.html]
+[test_localStorageSessionPrefOverride.html]
diff --git a/dom/tests/mochitest/localstorage/page_blank.html b/dom/tests/mochitest/localstorage/page_blank.html
new file mode 100644
index 000000000..157317d64
--- /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 000000000..d9648b271
--- /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 type="text/javascript" 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 000000000..8d539288b
--- /dev/null
+++ b/dom/tests/mochitest/localstorage/test_bug600307-DBOps.html
@@ -0,0 +1,166 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<title>bug 600307</title>
+
+<script type="text/javascript" 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">
+
+/*
+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()
+{
+ // 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();
+ is(localStorage.length, 0, "localStorage clean in case 4");
+
+ if (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();
+ 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();
+ 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");
+ 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");
+ 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 000000000..d080fbf75
--- /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 type="text/javascript" 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 000000000..bb19b90c0
--- /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 type="text/javascript" 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 000000000..c95cbca49
--- /dev/null
+++ b/dom/tests/mochitest/localstorage/test_cookieBlock.html
@@ -0,0 +1,42 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<title>cookie blocking test</title>
+
+<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+
+<script type="text/javascript">
+
+function startTest()
+{
+ try {
+ localStorage.setItem("blocked", "blockedvalue");
+ ok(false, "Exception for localStorage.setItem, ACCESS_DENY");
+ }
+ catch (ex) {
+ ok(true, "Exception for localStorage.setItem, ACCESS_DENY");
+ }
+
+ try {
+ localStorage.getItem("blocked");
+ ok(false, "Exception for localStorage.getItem, ACCESS_DENY");
+ }
+ catch (ex) {
+ ok(true, "Exception for localStorage.getItem, ACCESS_DENY");
+ }
+
+ SimpleTest.finish();
+}
+
+SimpleTest.waitForExplicitFinish();
+
+SpecialPowers.pushPermissions([{'type': 'cookie', 'allow': false, 'context': document}], startTest);
+
+</script>
+
+</head>
+
+<body>
+
+</body>
+</html>
diff --git a/dom/tests/mochitest/localstorage/test_cookieSession.html b/dom/tests/mochitest/localstorage/test_cookieSession.html
new file mode 100644
index 000000000..1fdd6f4d5
--- /dev/null
+++ b/dom/tests/mochitest/localstorage/test_cookieSession.html
@@ -0,0 +1,132 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<title>cookie per-session only test</title>
+
+<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+
+<script type="text/javascript">
+
+/*
+ Set cookie access to be just per session and store to the localStorage.
+ Content stored must prevail only for session of the browser, so it must
+ be accessible in another window we try to access that key in the same
+ storage.
+ */
+
+function pushCookie(aPermission, aNext) {
+ SpecialPowers.pushPermissions([{'type': 'cookie', 'allow': aPermission, 'context': document}], aNext);
+}
+
+function test1() {
+ localStorage.setItem("persistent1", "persistent value 1");
+ localStorage.setItem("persistent2", "persistent value 2");
+
+ pushCookie(SpecialPowers.Ci.nsICookiePermission.ACCESS_SESSION, test1_b);
+}
+
+function test1_b() {
+ localStorage.setItem("session only", "session value");
+ parent.is(localStorage.getItem("session only"), "session value");
+ parent.is(localStorage.getItem("persistent1"), "persistent value 1");
+ parent.is(localStorage.getItem("persistent2"), "persistent value 2");
+
+ window.location.search = '?2';
+}
+
+function test2()
+{
+ parent.is(localStorage.getItem("session only"), "session value", "Value present when cookies in session-only mode");
+ parent.is(localStorage.getItem("persistent1"), "persistent value 1", "Persistent value present");
+ parent.is(localStorage.getItem("persistent2"), "persistent value 2", "Persistent value present");
+
+ localStorage.setItem("persistent1", "changed persistent value 1");
+ localStorage.removeItem("persistent2");
+
+ parent.is(localStorage.getItem("session only"), "session value", "Value present when cookies in session-only mode");
+ parent.is(localStorage.getItem("persistent1"), "changed persistent value 1", "Persistent value present");
+ parent.is(localStorage.getItem("persistent2"), null, "Persistent value removed");
+
+ // This clear has to delete only changes made in session only mode
+ localStorage.clear();
+
+ parent.is(localStorage.getItem("session only"), null, "Value not present when cookies in session-only mode after delete");
+ parent.is(localStorage.getItem("persistent1"), null, "Persistent value not present in session only after delete");
+ parent.is(localStorage.getItem("persistent2"), null, "Persistent value not present in session only after delete");
+
+ localStorage.setItem("session only 2", "must be deleted on drop of session-only cookies permissions");
+
+ pushCookie(SpecialPowers.Ci.nsICookiePermission.ACCESS_DEFAULT, function() { window.location.search = '?3'; });
+}
+
+function test3() {
+ parent.is(localStorage.getItem("session only"), null, "No value when cookies are in default mode");
+ parent.is(localStorage.getItem("session only 2"), null, "No value when cookies are in default mode");
+ parent.is(localStorage.getItem("persistent1"), "persistent value 1", "Persistent value present");
+ parent.is(localStorage.getItem("persistent2"), "persistent value 2", "Persistent value present");
+
+ pushCookie(SpecialPowers.Ci.nsICookiePermission.ACCESS_SESSION, function() { window.location.search = '?4'; });
+}
+
+function test4() {
+ parent.is(localStorage.getItem("session only"), null, "Value not present when cookies in session-only mode after delete");
+ parent.is(localStorage.getItem("session only 2"), null, "Value not present when cookies in session-only mode after delete");
+ parent.is(localStorage.getItem("persistent1"), "persistent value 1", "Persistent value present again");
+ parent.is(localStorage.getItem("persistent2"), "persistent value 2", "Persistent value present again");
+
+ pushCookie(SpecialPowers.Ci.nsICookiePermission.ACCESS_DEFAULT, function() { window.location.search = '?5'; });
+}
+
+function test5() {
+ localStorage.clear();
+
+ parent.is(localStorage.getItem("session only"), null, "No value when cookies are in default mode");
+ parent.is(localStorage.getItem("persistent1"), null, "Persistent value not present after delete");
+ parent.is(localStorage.getItem("persistent2"), null, "Persistent value not present after delete");
+
+ pushCookie(SpecialPowers.Ci.nsICookiePermission.ACCESS_SESSION, function() { window.location.search = '?6'; });
+}
+
+function test6() {
+ parent.is(localStorage.getItem("session only"), null, "Value not present when cookies in session-only mode after delete");
+ parent.is(localStorage.getItem("session only 2"), null, "No value when cookies are in default mode");
+ parent.is(localStorage.getItem("persistent1"), null, "Persistent value not present in session only after delete");
+ parent.is(localStorage.getItem("persistent2"), null, "Persistent value not present in session only after delete");
+
+ parent.SimpleTest.finish();
+}
+
+function startTest() {
+ switch (location.search) {
+ case '?1':
+ test1();
+ break;
+ case '?2':
+ test2();
+ break;
+ case '?3':
+ test3();
+ break;
+ case '?4':
+ test4();
+ break;
+ case '?5':
+ test5();
+ break;
+ case '?6':
+ test6();
+ break;
+ default:
+ SimpleTest.waitForExplicitFinish();
+ var iframe = document.createElement('iframe');
+ iframe.src = 'test_cookieSession.html?1';
+ document.body.appendChild(iframe);
+ }
+}
+</script>
+
+</head>
+
+<body onload="startTest()">
+</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 000000000..04b88cfba
--- /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 type="text/javascript" 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 000000000..3f23945e2
--- /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 000000000..767a7d50c
--- /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 type="text/javascript" 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 > 0, "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 000000000..dbcf01fc2
--- /dev/null
+++ b/dom/tests/mochitest/localstorage/test_localStorageBasePrivateBrowsing_perwindowpb.html
@@ -0,0 +1,263 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<title>localStorage basic test, while in sesison only mode</title>
+
+<script type="application/javascript" 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">
+
+const Ci = Components.interfaces;
+var mainWindow;
+
+var prefBranch = Components.classes["@mozilla.org/preferences-service;1"]
+ .getService(Components.interfaces.nsIPrefBranch);
+prefBranch.setIntPref("browser.startup.page", 0);
+prefBranch.setCharPref("browser.startup.homepage_override.mstone", "ignore");
+
+function startTest() {
+ mainWindow = window.QueryInterface(Ci.nsIInterfaceRequestor)
+ .getInterface(Ci.nsIWebNavigation)
+ .QueryInterface(Ci.nsIDocShellTreeItem)
+ .rootTreeItem
+ .QueryInterface(Ci.nsIInterfaceRequestor)
+ .getInterface(Ci.nsIDOMWindow);
+
+ 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 onLoad() {
+ win.removeEventListener("load", onLoad, false);
+ win.addEventListener("DOMContentLoaded", function onInnerLoad() {
+ if (win.content.location.href == "about:privatebrowsing") {
+ win.gBrowser.loadURI(contentPage);
+ return;
+ }
+ win.removeEventListener("DOMContentLoaded", onInnerLoad, true);
+ SimpleTest.executeSoon(function() { aCallback(win); });
+ }, true);
+ win.gBrowser.loadURI(contentPage);
+ }, 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 000000000..c55a8e48d
--- /dev/null
+++ b/dom/tests/mochitest/localstorage/test_localStorageBaseSessionOnly.html
@@ -0,0 +1,205 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<title>localStorage basic test, while in sesison only mode</title>
+
+<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+
+<script type="text/javascript">
+
+function startTest()
+{
+ 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 000000000..99f3b1ace
--- /dev/null
+++ b/dom/tests/mochitest/localstorage/test_localStorageCookieSettings.html
@@ -0,0 +1,59 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<title>localStorage cookies settings test</title>
+
+<script type="text/javascript" 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>
+<iframe></iframe>
+
+<script type="text/javascript">
+
+SimpleTest.waitForExplicitFinish();
+
+// Set cookies behavior to "always reject".
+SpecialPowers.pushPrefEnv({"set": [["network.cookie.cookieBehavior", 2]]},
+ test1);
+
+function test1() {
+ try {
+ localStorage.setItem("contentkey", "test-value");
+ ok(false, "Setting localStorageItem should throw a security exception");
+ }
+ catch(ex) {
+ is(ex.name, "SecurityError");
+ }
+
+ // Set cookies behavior to "reject 3rd party"
+ SpecialPowers.pushPrefEnv({"set": [["network.cookie.cookieBehavior", 1]],
+ "clear": [["network.cookie.lifetimePolicy"]]},
+ test3);
+}
+
+function test3() {
+ try {
+ 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 = document.querySelector("iframe");
+ myframe.src = fileTest;
+}
+
+// Called by interOriginTest.js
+function doNextTest() {
+ SimpleTest.finish();
+}
+
+</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 000000000..88fd81e0b
--- /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 type="text/javascript" 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");
+ ok(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 000000000..22665b008
--- /dev/null
+++ b/dom/tests/mochitest/localstorage/test_localStorageFromChrome.xhtml
@@ -0,0 +1,58 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<title>localStorage basic test</title>
+
+<script type="text/javascript" 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">
+
+function startTest()
+{
+ 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, "", null);
+ var principal = ssm.createCodebasePrincipal(uri, {});
+ var storage = dsm.createStorage(window, 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 000000000..ecc0af8ee
--- /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 type="text/javascript" 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 000000000..96a93171c
--- /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 000000000..c1a441772
--- /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 000000000..35cdd86b3
--- /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 000000000..d34e0dbcd
--- /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 000000000..57e4fb5ab
--- /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 000000000..6aeefe6bc
--- /dev/null
+++ b/dom/tests/mochitest/localstorage/test_localStorageQuota.html
@@ -0,0 +1,111 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<title>localStorage and DOM quota test</title>
+
+<script type="text/javascript" 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:
+ slaveOrigin = "http://example.com";
+ slave.location = slaveOrigin + slavePath + "frameQuota.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 + "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;
+
+ // 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 + "frameQuota.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 + "frameQuota.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 + "frameQuota.html?add&C&success";
+ break;
+
+ case 8:
+ // 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:
+ // 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], ["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 000000000..24d3e4ba3
--- /dev/null
+++ b/dom/tests/mochitest/localstorage/test_localStorageQuotaPrivateBrowsing_perwindowpb.html
@@ -0,0 +1,192 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<title>localStorage and DOM quota test</title>
+
+<script type="text/javascript" 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();
+
+Components.utils.import("resource://gre/modules/Services.jsm");
+
+const Ci = Components.interfaces;
+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;
+
+try {
+ quota = Services.prefs.getIntPref("dom.storage.default_quota");
+} catch (ex) {
+ quota = 5 * 1024;
+}
+Services.prefs.setIntPref("browser.startup.page", 0);
+Services.prefs.setIntPref("dom.storage.default_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)
+ }, false);
+ 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:
+ slaveOrigin = "http://example.com";
+ slave.location = slaveOrigin + slavePath + "frameQuota.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 + "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;
+
+ // 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 + "frameQuota.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 + "frameQuota.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 + "frameQuota.html?add&C&success";
+ break;
+
+ case 8:
+ // Do a clean up...
+ // TODO Bug 455070, use just ?clear what invokes call
+ // of clear() in the target frame. W/o clear method we must
+ // call clear implemented as removeItem for each item in
+ // the localStorage.
+ slaveOrigin = "http://example.com";
+ slave.location = slaveOrigin + slavePath + "frameQuota.html?clear&A&";
+ break;
+
+ case 9:
+ // Do a clean up...
+ slaveOrigin = "http://test1.example.com";
+ slave.location = slaveOrigin + slavePath + "frameQuota.html?clear&B&";
+ break;
+
+ case 10:
+ // Do a clean up...
+ slaveOrigin = "https://test2.example.com";
+ slave.location = slaveOrigin + slavePath + "frameQuota.html?clear&C&";
+ break;
+
+ default:
+ Services.prefs.clearUserPref("browser.startup.page")
+ Services.prefs.setIntPref("dom.storage.default_quota", quota);
+ 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;
+ // Just fall through...
+ // Indication of successfully finished step of a test
+ 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(aWindow, aCallback) {
+ Services.obs.addObserver(function observer(aSubject, aTopic) {
+ if (aWindow == aSubject) {
+ Services.obs.removeObserver(observer, aTopic);
+ }
+
+ if (aWindow.content == null || aWindow.content.location.href != CONTENT_PAGE ) {
+ aWindow.addEventListener("DOMContentLoaded", function onInnerLoad() {
+ aWindow.removeEventListener("DOMContentLoaded", onInnerLoad, true);
+ SimpleTest.executeSoon(function() { aCallback(aWindow); });
+ }, true);
+
+ aWindow.gBrowser.loadURI(CONTENT_PAGE);
+ }
+ }, "browser-delayed-startup-finished", false);
+}
+
+function testOnWindow(aIsPrivate, callback) {
+ var mainWindow = window.QueryInterface(Ci.nsIInterfaceRequestor)
+ .getInterface(Ci.nsIWebNavigation)
+ .QueryInterface(Ci.nsIDocShellTreeItem)
+ .rootTreeItem
+ .QueryInterface(Ci.nsIInterfaceRequestor)
+ .getInterface(Ci.nsIDOMWindow);
+
+ var win = mainWindow.OpenBrowserWindow({private: aIsPrivate});
+ whenDelayedStartupFinished(win, function() { callback(win); });
+};
+</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 000000000..585da7ceb
--- /dev/null
+++ b/dom/tests/mochitest/localstorage/test_localStorageQuotaSessionOnly.html
@@ -0,0 +1,112 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<title>localStorage and DOM quota test</title>
+
+<script type="text/javascript" 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() {
+ SpecialPowers.pushPermissions([{'type': 'cookie', 'allow': SpecialPowers.Ci.nsICookiePermission.ACCESS_SESSION, 'context': document}], 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], ["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 000000000..1c1a70537
--- /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 type="text/javascript" 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], ["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 000000000..e1412eaef
--- /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 type="text/javascript" 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, false);
+
+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_localStorageSessionPrefOverride.html b/dom/tests/mochitest/localstorage/test_localStorageSessionPrefOverride.html
new file mode 100644
index 000000000..9fe6a48ec
--- /dev/null
+++ b/dom/tests/mochitest/localstorage/test_localStorageSessionPrefOverride.html
@@ -0,0 +1,54 @@
+<html>
+ <head>
+ <title>Local Storage Session Pref Override</title>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="text/javascript" src="/tests/SimpleTest/SpawnTask.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+ <script>
+ const ACCEPT_SESSION = 2;
+
+ add_task(function*() {
+ yield new Promise((resolve, reject) => {
+ SpecialPowers.pushPrefEnv({"set": [["network.cookie.lifetimePolicy",
+ ACCEPT_SESSION]]},
+ resolve);
+ });
+
+ // Before setting permission
+ yield new Promise((resolve) => {
+ var frame = document.createElement('iframe');
+ frame.src = "frameLocalStorageSessionOnly.html";
+
+ var listener = (e) => {
+ is(e.data, true, "Before adding permission should be session only");
+ window.removeEventListener('message', listener);
+ resolve();
+ };
+ window.addEventListener('message', listener);
+ document.body.appendChild(frame);
+ });
+
+ // After setting permission
+ yield new Promise((resolve) => {
+ SpecialPowers.pushPermissions([{"type": "cookie", "allow": 1, "context": document}],
+ resolve);
+ });
+
+ yield new Promise((resolve) => {
+ var frame = document.createElement('iframe');
+ frame.src = "frameLocalStorageSessionOnly.html";
+
+ var listener = (e) => {
+ is(e.data, false, "After adding permission should not be session only");
+ window.removeEventListener('message', listener);
+ resolve();
+ };
+ window.addEventListener('message', listener);
+ document.body.appendChild(frame);
+ });
+ });
+ </script>
+ </head>
+ <body>
+ </body>
+</html>
diff --git a/dom/tests/mochitest/localstorage/test_lowDeviceStorage.html b/dom/tests/mochitest/localstorage/test_lowDeviceStorage.html
new file mode 100644
index 000000000..046587150
--- /dev/null
+++ b/dom/tests/mochitest/localstorage/test_lowDeviceStorage.html
@@ -0,0 +1,76 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<title>Test localStorage usage while in a low device storage situation</title>
+
+<script type="text/javascript" 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">
+
+/*
+This test does the following:
+- Stores an item in localStorage.
+- Checks the stored value.
+- Emulates a low device storage situation.
+- Gets the stored item again.
+- Removes the stored item.
+- Fails storing a new value.
+- Emulates recovering from a low device storage situation.
+- Stores a new value.
+- Checks the stored value.
+*/
+
+function lowDeviceStorage(lowStorage) {
+ var data = lowStorage ? "full" : "free";
+ os().notifyObservers(null, "disk-space-watcher", data);
+}
+
+function startTest() {
+ // Add a test item.
+ localStorage.setItem("item", "value");
+ is(localStorage.getItem("item"), "value", "getItem()");
+
+ // Emulates a low device storage situation.
+ lowDeviceStorage(true);
+
+ // Checks that we can still access to the stored item.
+ is(localStorage.getItem("item"), "value",
+ "getItem() during a device storage situation");
+
+ // Removes the stored item.
+ localStorage.removeItem("item");
+ is(localStorage.getItem("item"), null,
+ "getItem() after removing the item");
+
+ // Fails storing a new item.
+ try {
+ localStorage.setItem("newItem", "value");
+ ok(false, "Storing a new item is expected to fail");
+ } catch(e) {
+ ok(true, "Got an expected exception " + e);
+ } finally {
+ is(localStorage.getItem("newItem"), null,
+ "setItem while device storage is low");
+ }
+
+ // Emulates recovering from a low device storage situation.
+ lowDeviceStorage(false);
+
+ // Add a test item after recovering from the low device storage situation.
+ localStorage.setItem("newItem", "value");
+ is(localStorage.getItem("newItem"), "value",
+ "getItem() with available storage");
+
+ SimpleTest.finish();
+}
+
+SimpleTest.waitForExplicitFinish();
+
+</script>
+
+</head>
+
+<body onload="startTest();">
+</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 000000000..f77c80ae2
--- /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 type="text/javascript" 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>