--- a/dom/base/NameSpaceConstants.h
+++ b/dom/base/NameSpaceConstants.h
@@ -19,11 +19,12 @@ static const int32_t kNameSpaceID_None =
#define kNameSpaceID_XLink 4
#define kNameSpaceID_XSLT 5
#define kNameSpaceID_XBL 6
#define kNameSpaceID_MathML 7
#define kNameSpaceID_RDF 8
#define kNameSpaceID_XUL 9
#define kNameSpaceID_SVG 10
#define kNameSpaceID_disabled_MathML 11
-#define kNameSpaceID_LastBuiltin 11 // last 'built-in' namespace
+#define kNameSpaceID_disabled_SVG 12
+#define kNameSpaceID_LastBuiltin 12 // last 'built-in' namespace
#endif // mozilla_dom_NameSpaceConstants_h__
--- a/dom/base/nsNameSpaceManager.cpp
+++ b/dom/base/nsNameSpaceManager.cpp
@@ -23,19 +23,21 @@
#include "mozilla/ClearOnShutdown.h"
#include "mozilla/dom/XBLChildrenElement.h"
#include "mozilla/dom/Element.h"
#include "mozilla/Preferences.h"
using namespace mozilla;
using namespace mozilla::dom;
+static const char* kPrefSVGDisabled = "svg.disabled";
static const char* kPrefMathMLDisabled = "mathml.disabled";
static const char* kObservedPrefs[] = {
kPrefMathMLDisabled,
+ kPrefSVGDisabled,
nullptr
};
StaticRefPtr<nsNameSpaceManager> nsNameSpaceManager::sInstance;
/* static */ nsNameSpaceManager*
nsNameSpaceManager::GetInstance() {
if (!sInstance) {
sInstance = new nsNameSpaceManager();
@@ -58,32 +60,34 @@ bool nsNameSpaceManager::Init()
NS_ENSURE_SUCCESS(rv, false)
#define REGISTER_DISABLED_NAMESPACE(uri, id) \
rv = AddDisabledNameSpace(dont_AddRef(uri), id); \
NS_ENSURE_SUCCESS(rv, false)
mozilla::Preferences::AddStrongObservers(this, kObservedPrefs);
mMathMLDisabled = mozilla::Preferences::GetBool(kPrefMathMLDisabled);
+ mSVGDisabled = mozilla::Preferences::GetBool(kPrefSVGDisabled);
// Need to be ordered according to ID.
MOZ_ASSERT(mURIArray.IsEmpty());
REGISTER_NAMESPACE(nsGkAtoms::empty, kNameSpaceID_None);
REGISTER_NAMESPACE(nsGkAtoms::nsuri_xmlns, kNameSpaceID_XMLNS);
REGISTER_NAMESPACE(nsGkAtoms::nsuri_xml, kNameSpaceID_XML);
REGISTER_NAMESPACE(nsGkAtoms::nsuri_xhtml, kNameSpaceID_XHTML);
REGISTER_NAMESPACE(nsGkAtoms::nsuri_xlink, kNameSpaceID_XLink);
REGISTER_NAMESPACE(nsGkAtoms::nsuri_xslt, kNameSpaceID_XSLT);
REGISTER_NAMESPACE(nsGkAtoms::nsuri_xbl, kNameSpaceID_XBL);
REGISTER_NAMESPACE(nsGkAtoms::nsuri_mathml, kNameSpaceID_MathML);
REGISTER_NAMESPACE(nsGkAtoms::nsuri_rdf, kNameSpaceID_RDF);
REGISTER_NAMESPACE(nsGkAtoms::nsuri_xul, kNameSpaceID_XUL);
REGISTER_NAMESPACE(nsGkAtoms::nsuri_svg, kNameSpaceID_SVG);
REGISTER_DISABLED_NAMESPACE(nsGkAtoms::nsuri_mathml, kNameSpaceID_disabled_MathML);
+ REGISTER_DISABLED_NAMESPACE(nsGkAtoms::nsuri_svg, kNameSpaceID_disabled_SVG);
#undef REGISTER_NAMESPACE
#undef REGISTER_DISABLED_NAMESPACE
return true;
}
nsresult
@@ -146,19 +150,21 @@ int32_t
nsNameSpaceManager::GetNameSpaceID(nsIAtom* aURI,
bool aInChromeDoc)
{
if (aURI == nsGkAtoms::_empty) {
return kNameSpaceID_None; // xmlns="", see bug 75700 for details
}
int32_t nameSpaceID;
- if (mMathMLDisabled &&
- mDisabledURIToIDTable.Get(aURI, &nameSpaceID) &&
- !aInChromeDoc) {
+ if (!aInChromeDoc
+ && (mMathMLDisabled || mSVGDisabled)
+ && mDisabledURIToIDTable.Get(aURI, &nameSpaceID)
+ && ((mMathMLDisabled && kNameSpaceID_disabled_MathML == nameSpaceID) ||
+ (mSVGDisabled && kNameSpaceID_disabled_SVG == nameSpaceID))) {
NS_POSTCONDITION(nameSpaceID >= 0, "Bogus namespace ID");
return nameSpaceID;
}
if (mURIToIDTable.Get(aURI, &nameSpaceID)) {
NS_POSTCONDITION(nameSpaceID >= 0, "Bogus namespace ID");
return nameSpaceID;
}
@@ -181,28 +187,59 @@ NS_NewElement(Element** aResult,
return NS_NewXULElement(aResult, ni.forget());
}
#endif
if (ns == kNameSpaceID_MathML) {
// If the mathml.disabled pref. is true, convert all MathML nodes into
// disabled MathML nodes by swapping the namespace.
nsNameSpaceManager* nsmgr = nsNameSpaceManager::GetInstance();
if ((nsmgr && !nsmgr->mMathMLDisabled) ||
- nsContentUtils::IsChromeDoc(ni->GetDocument())) {
+ nsContentUtils::IsSystemPrincipal(ni->GetDocument()->NodePrincipal())) {
return NS_NewMathMLElement(aResult, ni.forget());
}
RefPtr<mozilla::dom::NodeInfo> genericXMLNI =
ni->NodeInfoManager()->
GetNodeInfo(ni->NameAtom(), ni->GetPrefixAtom(),
kNameSpaceID_disabled_MathML, ni->NodeType(), ni->GetExtraName());
return NS_NewXMLElement(aResult, genericXMLNI.forget());
}
if (ns == kNameSpaceID_SVG) {
- return NS_NewSVGElement(aResult, ni.forget(), aFromParser);
+ // If the svg.disabled pref. is true, convert all SVG nodes into
+ // disabled SVG nodes by swapping the namespace.
+ nsNameSpaceManager* nsmgr = nsNameSpaceManager::GetInstance();
+ nsCOMPtr<nsILoadInfo> loadInfo;
+ bool SVGEnabled = false;
+
+ if (nsmgr && !nsmgr->mSVGDisabled) {
+ SVGEnabled = true;
+ } else {
+ nsCOMPtr<nsIChannel> channel = ni->GetDocument()->GetChannel();
+ // We don't have a channel for SVGs constructed inside a SVG script
+ if (channel) {
+ loadInfo = channel->GetLoadInfo();
+ }
+ }
+ if (SVGEnabled ||
+ nsContentUtils::IsSystemPrincipal(ni->GetDocument()->NodePrincipal()) ||
+ (loadInfo &&
+ (loadInfo->GetExternalContentPolicyType() == nsIContentPolicy::TYPE_IMAGE ||
+ loadInfo->GetExternalContentPolicyType() == nsIContentPolicy::TYPE_OTHER) &&
+ (nsContentUtils::IsSystemPrincipal(loadInfo->LoadingPrincipal()) ||
+ nsContentUtils::IsSystemPrincipal(loadInfo->TriggeringPrincipal())
+ )
+ )
+ ) {
+ return NS_NewSVGElement(aResult, ni.forget(), aFromParser);
+ }
+ RefPtr<mozilla::dom::NodeInfo> genericXMLNI =
+ ni->NodeInfoManager()->
+ GetNodeInfo(ni->NameAtom(), ni->GetPrefixAtom(),
+ kNameSpaceID_disabled_SVG, ni->NodeType(), ni->GetExtraName());
+ return NS_NewXMLElement(aResult, genericXMLNI.forget());
}
if (ns == kNameSpaceID_XBL && ni->Equals(nsGkAtoms::children)) {
NS_ADDREF(*aResult = new XBLChildrenElement(ni.forget()));
return NS_OK;
}
return NS_NewXMLElement(aResult, ni.forget());
}
@@ -257,10 +294,11 @@ NS_IMPL_ISUPPORTS(nsNameSpaceManager,
nsIObserver)
// nsIObserver
NS_IMETHODIMP
nsNameSpaceManager::Observe(nsISupports* aObject, const char* aTopic,
const char16_t* aMessage)
{
mMathMLDisabled = mozilla::Preferences::GetBool(kPrefMathMLDisabled);
+ mSVGDisabled = mozilla::Preferences::GetBool(kPrefSVGDisabled);
return NS_OK;
}
--- a/dom/base/nsNameSpaceManager.h
+++ b/dom/base/nsNameSpaceManager.h
@@ -61,16 +61,17 @@ public:
bool aInChromeDoc);
int32_t GetNameSpaceID(nsIAtom* aURI,
bool aInChromeDoc);
bool HasElementCreator(int32_t aNameSpaceID);
static nsNameSpaceManager* GetInstance();
bool mMathMLDisabled;
+ bool mSVGDisabled;
private:
bool Init();
nsresult AddNameSpace(already_AddRefed<nsIAtom> aURI, const int32_t aNameSpaceID);
nsresult AddDisabledNameSpace(already_AddRefed<nsIAtom> aURI, const int32_t aNameSpaceID);
~nsNameSpaceManager() {};
nsDataHashtable<nsISupportsHashKey, int32_t> mURIToIDTable;
--- a/dom/xml/nsXMLContentSink.cpp
+++ b/dom/xml/nsXMLContentSink.cpp
@@ -1054,16 +1054,19 @@ nsXMLContentSink::HandleEndElement(const
// elements do not get pushed on the stack, the template
// element content is pushed instead.
bool isTemplateElement = debugTagAtom == nsGkAtoms::_template &&
debugNameSpaceID == kNameSpaceID_XHTML;
NS_ASSERTION(content->NodeInfo()->Equals(debugTagAtom, debugNameSpaceID) ||
(debugNameSpaceID == kNameSpaceID_MathML &&
content->NodeInfo()->NamespaceID() == kNameSpaceID_disabled_MathML &&
content->NodeInfo()->Equals(debugTagAtom)) ||
+ (debugNameSpaceID == kNameSpaceID_SVG &&
+ content->NodeInfo()->NamespaceID() == kNameSpaceID_disabled_SVG &&
+ content->NodeInfo()->Equals(debugTagAtom)) ||
isTemplateElement, "Wrong element being closed");
#endif
result = CloseElement(content);
if (mCurrentHead == content) {
mCurrentHead = nullptr;
}
--- a/layout/svg/moz.build
+++ b/layout/svg/moz.build
@@ -2,16 +2,24 @@
# vim: set filetype=python:
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
with Files('**'):
BUG_COMPONENT = ('Core', 'SVG')
+if CONFIG['ENABLE_TESTS']:
+ MOCHITEST_MANIFESTS += [
+ 'tests/mochitest.ini',
+]
+ MOCHITEST_CHROME_MANIFESTS += [
+ 'tests/chrome.ini',
+]
+
EXPORTS += [
'nsFilterInstance.h',
'nsSVGEffects.h',
'nsSVGFilterInstance.h',
'nsSVGForeignObjectFrame.h',
'nsSVGIntegrationUtils.h',
'nsSVGUtils.h',
'SVGImageContext.h',
new file mode 100644
--- /dev/null
+++ b/layout/svg/tests/chrome.ini
@@ -0,0 +1,6 @@
+[DEFAULT]
+
+support-files =
+ svg_example_test.html
+
+[test_disabled_chrome.html]
new file mode 100644
--- /dev/null
+++ b/layout/svg/tests/mochitest.ini
@@ -0,0 +1,3 @@
+[DEFAULT]
+
+[test_disabled.html]
new file mode 100644
--- /dev/null
+++ b/layout/svg/tests/svg_example_test.html
@@ -0,0 +1,7 @@
+<svg id="layout" viewBox="0 0 120 120" version="1.1"
+ xmlns="http://www.w3.org/2000/svg">
+ <circle cx="60" cy="60" r="50"/>
+</svg>
+
+<svg id="svgel">
+</svg>
new file mode 100644
--- /dev/null
+++ b/layout/svg/tests/test_disabled.html
@@ -0,0 +1,59 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+Copied from
+https://bugzilla.mozilla.org/show_bug.cgi?id=744830
+-->
+<head>
+ <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=166235">Mozilla Bug 166235</a>
+<div id="testnodes"><span>hi</span> there <!-- mon ami --></div>
+<pre id="test">
+<script type="application/javascript">
+ SimpleTest.waitForExplicitFinish();
+ SpecialPowers.pushPrefEnv({"set": [["svg.disabled", true]]}, doTest);
+ function doTest() {
+ let t = document.getElementById('testnodes');
+ t.innerHTML = null;
+ t.appendChild(document.createElementNS("http://www.w3.org/2000/svg", "svg:svg"));
+ t.firstChild.textContent = "<foo>";
+ is(t.innerHTML, "<svg:svg><foo></svg:svg>");
+
+ // This test crashes if the style tags are not handled correctly
+ t.innerHTML = `<svg version="1.1">
+ <style>
+ circle {
+ fill: currentColor;
+ }
+ </style>
+ <g><circle cx="25.8" cy="9.3" r="1.5"/></g>
+ </svg>
+ `;
+ is(t.firstChild.tagName.toLowerCase(), 'svg');
+
+ t.innerHTML = null;
+ t.appendChild(document.createElementNS("http://www.w3.org/2000/svg", "svg"));
+ is(t.firstChild.namespaceURI, "http://www.w3.org/2000/svg");
+ t.firstChild.appendChild(document.createElementNS("http://www.w3.org/2000/svg", "script"));
+ is(t.firstChild.firstChild.namespaceURI, "http://www.w3.org/2000/svg");
+ t.firstChild.firstChild.textContent = "1&2<3>4\xA0";
+ is(t.innerHTML, '<svg><script>1&2<3>4 \u003C/script></svg>');
+
+ t.innerHTML = null;
+ t.appendChild(document.createElementNS("http://www.w3.org/2000/svg", "svg"));
+ is(t.firstChild.namespaceURI, "http://www.w3.org/2000/svg");
+ t.firstChild.appendChild(document.createElementNS("http://www.w3.org/2000/svg", "style"));
+ is(t.firstChild.firstChild.namespaceURI, "http://www.w3.org/2000/svg");
+ t.firstChild.firstChild.textContent = "1&2<3>4\xA0";
+ is(t.innerHTML, '<svg><style>1&2<3>4 \u003C/style></svg>');
+
+ SimpleTest.finish();
+ }
+</script>
+</pre>
+</body>
+</html>
+
new file mode 100644
--- /dev/null
+++ b/layout/svg/tests/test_disabled_chrome.html
@@ -0,0 +1,53 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=744830
+-->
+<head>
+ <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SpawnTask.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=166235">Mozilla Bug 166235</a>
+<div id="testnodes"><span>hi</span> there <!-- mon ami --></div>
+<pre id="test">
+<script type="application/javascript">
+ add_task(function* () {
+ const initialPrefValue = SpecialPowers.getBoolPref("svg.disabled");
+ SpecialPowers.setBoolPref("svg.disabled", true);
+ const Cu = SpecialPowers.Components.utils;
+ const { ContentTaskUtils } = Cu.import("resource://testing-common/ContentTaskUtils.jsm", {});
+ let t = document.getElementById('testnodes');
+
+ let url = 'chrome://mochitests/content/chrome/layout/svg/tests/svg_example_test.html'
+ const chromeIframeEl = document.createElement('iframe');
+ let chromeLoadPromise = ContentTaskUtils.waitForEvent(chromeIframeEl, 'load', false);
+ chromeIframeEl.src = url;
+ t.appendChild(chromeIframeEl);
+
+ yield chromeLoadPromise;
+ const chromeBR = chromeIframeEl.contentDocument.body.getBoundingClientRect();
+
+ url = "http://mochi.test:8888/chrome/layout/svg/tests/svg_example_test.html";
+ const iframeEl = document.createElement('iframe');
+ iframeEl.src = url;
+ let loadPromise = ContentTaskUtils.waitForEvent(iframeEl, 'load', false);
+ t.appendChild(iframeEl);
+ yield loadPromise;
+
+ const contentBR = iframeEl.contentDocument.body.getBoundingClientRect();
+
+yield new Promise(_ => setTimeout(_, 1000));
+ ok(chromeBR.height > contentBR.height, "Chrome content height should be bigger than content due to layout");
+
+ ok(!("hasExtension" in iframeEl.contentDocument.getElementById('svgel')), 'SVG is disabled so no hasExtension support is available in content iframe');
+ ok(chromeIframeEl.contentDocument.getElementById('svgel').hasExtension("http://www.w3.org/1998/Math/MathML"), 'SVG namespace support is enabled in chrome iframe');
+
+ SpecialPowers.setBoolPref("svg.disabled", initialPrefValue);
+ });
+</script>
+</pre>
+</body>
+</html>
+
--- a/modules/libpref/init/all.js
+++ b/modules/libpref/init/all.js
@@ -2876,16 +2876,19 @@ pref("dom.ipc.plugins.asyncInit.enabled"
pref("dom.ipc.plugins.asyncdrawing.enabled", false);
#else
// Allow the AsyncDrawing mode to be used for plugins in dev channels.
pref("dom.ipc.plugins.asyncdrawing.enabled", true);
#endif
pref("dom.ipc.processCount", 1);
+// Disable support for SVG
+pref("svg.disabled", false);
+
// Override default dom.ipc.processCount for some remote content process types.
pref("dom.ipc.processCount.webLargeAllocation", 2);
// Pref to control whether we use separate content processes for top-level load
// of file:// URIs.
#if defined(NIGHTLY_BUILD)
pref("browser.tabs.remote.separateFileUriProcess", true);
#else
--- a/parser/html/nsHtml5DocumentBuilder.cpp
+++ b/parser/html/nsHtml5DocumentBuilder.cpp
@@ -5,16 +5,17 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "nsHtml5DocumentBuilder.h"
#include "nsIStyleSheetLinkingElement.h"
#include "nsStyleLinkElement.h"
#include "nsScriptLoader.h"
#include "nsIHTMLDocument.h"
+#include "nsNameSpaceManager.h"
NS_IMPL_CYCLE_COLLECTION_INHERITED(nsHtml5DocumentBuilder, nsContentSink,
mOwnedElements)
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(nsHtml5DocumentBuilder)
NS_INTERFACE_MAP_END_INHERITING(nsContentSink)
NS_IMPL_ADDREF_INHERITED(nsHtml5DocumentBuilder, nsContentSink)
@@ -52,28 +53,31 @@ nsHtml5DocumentBuilder::SetDocumentChars
mDocument->SetDocumentCharacterSetSource(aCharsetSource);
mDocument->SetDocumentCharacterSet(aCharset);
}
}
void
nsHtml5DocumentBuilder::UpdateStyleSheet(nsIContent* aElement)
{
+ nsCOMPtr<nsIStyleSheetLinkingElement> ssle(do_QueryInterface(aElement));
+ if (!ssle) {
+ MOZ_ASSERT(nsNameSpaceManager::GetInstance()->mSVGDisabled, "Node didn't QI to style, but SVG wasn't disabled.");
+ return;
+ }
+
// Break out of the doc update created by Flush() to zap a runnable
// waiting to call UpdateStyleSheet without the right observer
EndDocUpdate();
if (MOZ_UNLIKELY(!mParser)) {
// EndDocUpdate ran stuff that called nsIParser::Terminate()
return;
}
- nsCOMPtr<nsIStyleSheetLinkingElement> ssle(do_QueryInterface(aElement));
- NS_ASSERTION(ssle, "Node didn't QI to style.");
-
ssle->SetEnableUpdates(true);
bool willNotify;
bool isAlternate;
nsresult rv = ssle->UpdateStyleSheet(mRunsToCompletion ? nullptr : this,
&willNotify,
&isAlternate);
if (NS_SUCCEEDED(rv) && willNotify && !isAlternate && !mRunsToCompletion) {
--- a/parser/html/nsHtml5TreeOperation.cpp
+++ b/parser/html/nsHtml5TreeOperation.cpp
@@ -819,18 +819,21 @@ nsHtml5TreeOperation::Perform(nsHtml5Tre
}
case eTreeOpStreamEnded: {
aBuilder->DidBuildModel(false); // this causes a notifications flush anyway
return NS_OK;
}
case eTreeOpSetStyleLineNumber: {
nsIContent* node = *(mOne.node);
nsCOMPtr<nsIStyleSheetLinkingElement> ssle = do_QueryInterface(node);
- NS_ASSERTION(ssle, "Node didn't QI to style.");
- ssle->SetLineNumber(mFour.integer);
+ if (ssle) {
+ ssle->SetLineNumber(mFour.integer);
+ } else {
+ MOZ_ASSERT(nsNameSpaceManager::GetInstance()->mSVGDisabled, "Node didn't QI to style, but SVG wasn't disabled.");
+ }
return NS_OK;
}
case eTreeOpSetScriptLineNumberAndFreeze: {
nsIContent* node = *(mOne.node);
nsCOMPtr<nsIScriptElement> sele = do_QueryInterface(node);
NS_ASSERTION(sele, "Node didn't QI to script.");
sele->SetScriptLineNumber(mFour.integer);
sele->FreezeUriAsyncDefer();
new file mode 100644
--- /dev/null
+++ b/toolkit/components/contextualidentity/tests/unit/test_basic.html
@@ -0,0 +1,71 @@
+"use strict";
+
+do_get_profile();
+
+const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
+
+Cu.import("resource://gre/modules/ContextualIdentityService.jsm");
+
+const TEST_STORE_FILE_NAME = "test-containers.json";
+
+let cis;
+
+// Basic tests
+add_task(function() {
+ ok(!!ContextualIdentityService, "ContextualIdentityService exists");
+
+ cis = ContextualIdentityService.createNewInstanceForTesting(TEST_STORE_FILE_NAME);
+ ok(!!cis, "We have our instance of ContextualIdentityService");
+
+ equal(cis.getIdentities().length, 4, "By default, 4 containers.");
+ equal(cis.getIdentityFromId(0), null, "No identity with id 0");
+
+ ok(!!cis.getIdentityFromId(1), "Identity 1 exists");
+ ok(!!cis.getIdentityFromId(2), "Identity 2 exists");
+ ok(!!cis.getIdentityFromId(3), "Identity 3 exists");
+ ok(!!cis.getIdentityFromId(4), "Identity 4 exists");
+});
+
+// Create a new identity
+add_task(function() {
+ equal(cis.getIdentities().length, 4, "By default, 4 containers.");
+
+ let identity = cis.create("New Container", "Icon", "Color");
+ ok(!!identity, "New container created");
+ equal(identity.name, "New Container", "Name matches");
+ equal(identity.icon, "Icon", "Icon matches");
+ equal(identity.color, "Color", "Color matches");
+
+ equal(cis.getIdentities().length, 5, "Expected 5 containers.");
+
+ ok(!!cis.getIdentityFromId(identity.userContextId), "Identity exists");
+ equal(cis.getIdentityFromId(identity.userContextId).name, "New Container", "Identity name is OK");
+ equal(cis.getIdentityFromId(identity.userContextId).icon, "Icon", "Identity icon is OK");
+ equal(cis.getIdentityFromId(identity.userContextId).color, "Color", "Identity color is OK");
+ equal(cis.getUserContextLabel(identity.userContextId), "New Container", "Identity label is OK");
+});
+
+// Remove an identity
+add_task(function() {
+ equal(cis.getIdentities().length, 5, "Expected 5 containers.");
+
+ equal(cis.remove(-1), false, "cis.remove() returns false if identity doesn't exist.");
+ equal(cis.remove(1), true, "cis.remove() returns true if identity exists.");
+
+ equal(cis.getIdentities().length, 4, "Expected 4 containers.");
+});
+
+// Update an identity
+add_task(function() {
+ ok(!!cis.getIdentityFromId(2), "Identity 2 exists");
+
+ equal(cis.update(-1, "Container", "Icon", "Color"), false, "Update returns true if everything is OK");
+
+ equal(cis.update(2, "Container", "Icon", "Color"), true, "Update returns true if everything is OK");
+
+ ok(!!cis.getIdentityFromId(2), "Identity exists");
+ equal(cis.getIdentityFromId(2).name, "Container", "Identity name is OK");
+ equal(cis.getIdentityFromId(2).icon, "Icon", "Identity icon is OK");
+ equal(cis.getIdentityFromId(2).color, "Color", "Identity color is OK");
+ equal(cis.getUserContextLabel(2), "Container", "Identity label is OK");
+});