author | Ryan VanderMeulen <ryanvm@gmail.com> |
Sun, 13 Mar 2016 19:08:03 -0400 | |
changeset 288515 | f0c0480732d36153e8839c7f17394d45f679f87d |
parent 288478 | 985daf7c2e1ee1e08a005bf72fd8731c5f26a6bc (current diff) |
parent 288514 | 080f495f9e41044e8de7cbd66909199e83b977cc (diff) |
child 288516 | 2bef59a4476a99e0796bde9502c1bf0744f97182 |
child 288538 | 0ce67740545443ec87c0afd2d3d8b146dc517466 |
push id | 30082 |
push user | ryanvm@gmail.com |
push date | Sun, 13 Mar 2016 23:08:35 +0000 |
treeherder | mozilla-central@f0c0480732d3 [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | merge |
milestone | 48.0a1 |
first release with | nightly linux32
f0c0480732d3
/
48.0a1
/
20160314030215
/
files
nightly linux64
f0c0480732d3
/
48.0a1
/
20160314030215
/
files
nightly mac
f0c0480732d3
/
48.0a1
/
20160314030215
/
files
nightly win32
f0c0480732d3
/
48.0a1
/
20160314030215
/
files
nightly win64
f0c0480732d3
/
48.0a1
/
20160314030215
/
files
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
releases | nightly linux32
48.0a1
/
20160314030215
/
pushlog to previous
nightly linux64
48.0a1
/
20160314030215
/
pushlog to previous
nightly mac
48.0a1
/
20160314030215
/
pushlog to previous
nightly win32
48.0a1
/
20160314030215
/
pushlog to previous
nightly win64
48.0a1
/
20160314030215
/
pushlog to previous
|
--- a/b2g/app/b2g.js +++ b/b2g/app/b2g.js @@ -437,19 +437,16 @@ pref("dom.meta-viewport.enabled", true); #endif // SMS/MMS pref("dom.sms.enabled", true); //The waiting time in network manager. pref("network.gonk.ms-release-mms-connection", 30000); -// WebContacts -pref("dom.mozContacts.enabled", true); - // Shortnumber matching needed for e.g. Brazil: // 03187654321 can be found with 87654321 pref("dom.phonenumber.substringmatching.BR", 8); pref("dom.phonenumber.substringmatching.CO", 10); pref("dom.phonenumber.substringmatching.VE", 7); pref("dom.phonenumber.substringmatching.CL", 8); pref("dom.phonenumber.substringmatching.PE", 7);
--- a/browser/extensions/pocket/bootstrap.js +++ b/browser/extensions/pocket/bootstrap.js @@ -104,17 +104,18 @@ PocketAboutPage.prototype = { getURIFlags: function(aURI) { return Ci.nsIAboutModule.ALLOW_SCRIPT | Ci.nsIAboutModule.URI_SAFE_FOR_UNTRUSTED_CONTENT | Ci.nsIAboutModule.HIDE_FROM_ABOUTABOUT | Ci.nsIAboutModule.MAKE_UNLINKABLE; }, newChannel: function(aURI, aLoadInfo) { - let channel = Services.io.newChannelFromURIWithLoadInfo(this.chromeURL, + let newURI = Services.io.newURI(this.chromeURL, null, null); + let channel = Services.io.newChannelFromURIWithLoadInfo(newURI, aLoadInfo); channel.originalURI = aURI; return channel; }, createInstance: function(outer, iid) { if (outer != null) { throw Cr.NS_ERROR_NO_AGGREGATION;
--- a/browser/themes/shared/identity-block/identity-block.inc.css +++ b/browser/themes/shared/identity-block/identity-block.inc.css @@ -50,18 +50,22 @@ #urlbar[pageproxystate="valid"] > #identity-box.verifiedIdentity { color: var(--identity-box-verified-color); } #urlbar[pageproxystate="valid"] > #identity-box.chromeUI { color: var(--identity-box-chrome-color); } -#identity-icon-labels { - padding-inline-start: 2px; +#identity-icon-labels:-moz-locale-dir(ltr) { + padding-left: 2px; +} + +#identity-icon-labels:-moz-locale-dir(rtl) { + padding-right: 2px; } #notification-popup-box:not([hidden]) + #identity-box { padding-inline-start: 10px; border-radius: 0; } @conditionalForwardWithUrlbar@ > #urlbar > #identity-box {
--- a/config/check_spidermonkey_style.py +++ b/config/check_spidermonkey_style.py @@ -61,16 +61,17 @@ included_inclnames_to_ignore = set([ 'ffi.h', # generated in ctypes/libffi/ 'devtools/sharkctl.h', # we ignore devtools/ in general 'devtools/Instruments.h', # we ignore devtools/ in general 'double-conversion.h', # strange MFBT case 'javascript-trace.h', # generated in $OBJDIR if HAVE_DTRACE is defined 'jsautokw.h', # generated in $OBJDIR 'jscustomallocator.h', # provided by embedders; allowed to be missing 'js-config.h', # generated in $OBJDIR + 'fdlibm.h', # fdlibm 'pratom.h', # NSPR 'prcvar.h', # NSPR 'prerror.h', # NSPR 'prinit.h', # NSPR 'prlink.h', # NSPR 'prlock.h', # NSPR 'prprf.h', # NSPR 'prthread.h', # NSPR
new file mode 100644 --- /dev/null +++ b/config/external/fdlibm/moz.build @@ -0,0 +1,14 @@ +# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*- +# 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/. + +Library('fdlibm') + +with Files('**'): + BUG_COMPONENT = ('Core', 'JavaScript Engine') + +DIRS += [ + '../../../modules/fdlibm', +]
--- a/dom/animation/AnimationEffectTiming.cpp +++ b/dom/animation/AnimationEffectTiming.cpp @@ -14,34 +14,52 @@ namespace mozilla { namespace dom { JSObject* AnimationEffectTiming::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) { return AnimationEffectTimingBinding::Wrap(aCx, this, aGivenProto); } -void -AnimationEffectTiming::NotifyTimingUpdate() +static inline void +PostSpecifiedTimingUpdated(KeyframeEffect* aEffect) { - if (mEffect) { - mEffect->NotifySpecifiedTimingUpdated(); + if (aEffect) { + aEffect->NotifySpecifiedTimingUpdated(); } } void AnimationEffectTiming::SetEndDelay(double aEndDelay) { TimeDuration endDelay = TimeDuration::FromMilliseconds(aEndDelay); if (mTiming.mEndDelay == endDelay) { return; } mTiming.mEndDelay = endDelay; - NotifyTimingUpdate(); + PostSpecifiedTimingUpdated(mEffect); +} + +void +AnimationEffectTiming::SetIterationStart(double aIterationStart, + ErrorResult& aRv) +{ + if (mTiming.mIterationStart == aIterationStart) { + return; + } + + TimingParams::ValidateIterationStart(aIterationStart, aRv); + if (aRv.Failed()) { + return; + } + + mTiming.mIterationStart = aIterationStart; + + PostSpecifiedTimingUpdated(mEffect); } void AnimationEffectTiming::SetDuration(const UnrestrictedDoubleOrString& aDuration, ErrorResult& aRv) { Maybe<StickyTimeDuration> newDuration = TimingParams::ParseDuration(aDuration, aRv); @@ -50,13 +68,13 @@ AnimationEffectTiming::SetDuration(const } if (mTiming.mDuration == newDuration) { return; } mTiming.mDuration = newDuration; - NotifyTimingUpdate(); + PostSpecifiedTimingUpdated(mEffect); } } // namespace dom } // namespace mozilla
--- a/dom/animation/AnimationEffectTiming.h +++ b/dom/animation/AnimationEffectTiming.h @@ -20,20 +20,20 @@ public: : AnimationEffectTimingReadOnly(aTiming) , mEffect(aEffect) { } JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override; void Unlink() override { mEffect = nullptr; } void SetEndDelay(double aEndDelay); + void SetIterationStart(double aIterationStart, ErrorResult& aRv); void SetDuration(const UnrestrictedDoubleOrString& aDuration, ErrorResult& aRv); private: - void NotifyTimingUpdate(); KeyframeEffect* MOZ_NON_OWNING_REF mEffect; }; } // namespace dom } // namespace mozilla #endif // mozilla_dom_AnimationEffectTiming_h
--- a/dom/animation/AnimationUtils.cpp +++ b/dom/animation/AnimationUtils.cpp @@ -5,20 +5,23 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "AnimationUtils.h" #include "nsCSSParser.h" // For nsCSSParser #include "nsDebug.h" #include "nsIAtom.h" #include "nsIContent.h" +#include "nsIDocument.h" +#include "nsGlobalWindow.h" #include "nsString.h" #include "mozilla/Attributes.h" #include "mozilla/ComputedTimingFunction.h" // ComputedTimingFunction #include "mozilla/dom/Element.h" // For dom::Element +#include "xpcpublic.h" // For xpc::CurrentWindowOrNull namespace mozilla { /* static */ void AnimationUtils::LogAsyncAnimationFailure(nsCString& aMessage, const nsIContent* aContent) { if (aContent) { @@ -94,9 +97,19 @@ AnimationUtils::ParseEasing(const dom::E break; default: MOZ_ASSERT_UNREACHABLE("unexpected animation-timing-function unit"); break; } return Nothing(); } +/* static */ nsIDocument* +AnimationUtils::GetCurrentRealmDocument(JSContext* aCx) +{ + nsGlobalWindow* win = xpc::CurrentWindowOrNull(aCx); + if (!win) { + return nullptr; + } + return win->GetDoc(); +} + } // namespace mozilla
--- a/dom/animation/AnimationUtils.h +++ b/dom/animation/AnimationUtils.h @@ -7,42 +7,44 @@ #ifndef mozilla_dom_AnimationUtils_h #define mozilla_dom_AnimationUtils_h #include "mozilla/TimeStamp.h" #include "mozilla/dom/Nullable.h" #include "nsStringFwd.h" class nsIContent; +class nsIDocument; +struct JSContext; namespace mozilla { class ComputedTimingFunction; namespace dom { class Element; } class AnimationUtils { public: static dom::Nullable<double> - TimeDurationToDouble(const dom::Nullable<TimeDuration>& aTime) + TimeDurationToDouble(const dom::Nullable<TimeDuration>& aTime) { dom::Nullable<double> result; if (!aTime.IsNull()) { result.SetValue(aTime.Value().ToMilliseconds()); } return result; } static dom::Nullable<TimeDuration> - DoubleToTimeDuration(const dom::Nullable<double>& aTime) + DoubleToTimeDuration(const dom::Nullable<double>& aTime) { dom::Nullable<TimeDuration> result; if (!aTime.IsNull()) { result.SetValue(TimeDuration::FromMilliseconds(aTime.Value())); } return result; @@ -52,14 +54,20 @@ public: const nsIContent* aContent = nullptr); /** * Parses a CSS <single-transition-timing-function> value from * aEasing into a ComputedTimingFunction. If parsing fails, Nothing() will * be returned. */ static Maybe<ComputedTimingFunction> - ParseEasing(const dom::Element* aTarget, const nsAString& aEasing); + ParseEasing(const dom::Element* aTarget, const nsAString& aEasing); + + /** + * Get the document from the JS context to use when parsing CSS properties. + */ + static nsIDocument* + GetCurrentRealmDocument(JSContext* aCx); }; } // namespace mozilla #endif
--- a/dom/animation/TimingParams.cpp +++ b/dom/animation/TimingParams.cpp @@ -59,21 +59,27 @@ TimingParamsFromOptionsUnion( if (target.IsElement()) { targetElement = &target.GetAsElement(); } else { targetElement = target.GetAsCSSPseudoElement().ParentElement(); } } const dom::AnimationEffectTimingProperties& timing = GetTimingProperties(aOptions); + Maybe<StickyTimeDuration> duration = TimingParams::ParseDuration(timing.mDuration, aRv); if (aRv.Failed()) { return result; } + TimingParams::ValidateIterationStart(timing.mIterationStart, aRv); + if (aRv.Failed()) { + return result; + } + result.mDuration = duration; result.mDelay = TimeDuration::FromMilliseconds(timing.mDelay); result.mEndDelay = TimeDuration::FromMilliseconds(timing.mEndDelay); result.mIterations = timing.mIterations; result.mIterationStart = timing.mIterationStart; result.mDirection = timing.mDirection; result.mFill = timing.mFill; result.mFunction =
--- a/dom/animation/TimingParams.h +++ b/dom/animation/TimingParams.h @@ -44,31 +44,40 @@ struct TimingParams ErrorResult& aRv); // Range-checks and validates an UnrestrictedDoubleOrString or // OwningUnrestrictedDoubleOrString object and converts to a // StickyTimeDuration value or Nothing() if aDuration is "auto". // Caller must check aRv.Failed(). template <class DoubleOrString> static Maybe<StickyTimeDuration> ParseDuration(DoubleOrString& aDuration, - ErrorResult& aRv) { + ErrorResult& aRv) + { Maybe<StickyTimeDuration> result; if (aDuration.IsUnrestrictedDouble()) { double durationInMs = aDuration.GetAsUnrestrictedDouble(); if (durationInMs >= 0) { result.emplace(StickyTimeDuration::FromMilliseconds(durationInMs)); return result; } } else if (aDuration.GetAsString().EqualsLiteral("auto")) { return result; } aRv.Throw(NS_ERROR_DOM_TYPE_ERR); return result; } + static void ValidateIterationStart(double aIterationStart, + ErrorResult& aRv) + { + if (aIterationStart < 0) { + aRv.Throw(NS_ERROR_DOM_TYPE_ERR); + } + } + // mDuration.isNothing() represents the "auto" value Maybe<StickyTimeDuration> mDuration; TimeDuration mDelay; // Initializes to zero TimeDuration mEndDelay; double mIterations = 1.0; // Can be NaN, negative, +/-Infinity double mIterationStart = 0.0; dom::PlaybackDirection mDirection = dom::PlaybackDirection::Normal; dom::FillMode mFill = dom::FillMode::Auto;
--- a/dom/base/test/chrome.ini +++ b/dom/base/test/chrome.ini @@ -9,16 +9,17 @@ support-files = [test_anonymousContent_xul_window.xul] [test_bug715041.xul] [test_bug715041_removal.xul] [test_domrequesthelper.xul] [test_url.xul] [test_console.xul] [test_navigator_resolve_identity_xrays.xul] +support-files = file_navigator_resolve_identity_xrays.xul [test_sendQueryContentAndSelectionSetEvent.html] [test_bug1016960.html] [test_bug357450.js] [test_copypaste.xul] [test_messagemanager_principal.html] [test_messagemanager_send_principal.html] skip-if = buildapp == 'mulet' [test_bug945152.html]
new file mode 100644 --- /dev/null +++ b/dom/base/test/file_navigator_resolve_identity_xrays.xul @@ -0,0 +1,35 @@ +<?xml version="1.0"?> +<?xml-stylesheet type="text/css" href="chrome://global/skin"?> +<?xml-stylesheet type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"?> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=985827 +--> +<window title="Mozilla Bug 985827" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> + <script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/> + + <iframe id="t"></iframe> + + <!-- test code goes here --> + <script type="application/javascript"> + <![CDATA[ + /** Test for Bug 985827 **/ + + addLoadEvent(function() { + var ok = parent.ok; + var is = parent.is; + + var nav = document.getElementById("t").contentWindow.navigator; + + ok(Components.utils.isXrayWrapper(nav), "Should have an Xray here"); + + // Test WebIDL NavigatorProperty objects + is(typeof nav.mozContacts, "object", "Should have a mozContacts object"); + is(nav.mozContacts, nav.mozContacts, + "Should have gotten the same mozContacts object again"); + }); + + ]]> + </script> +</window>
--- a/dom/base/test/test_navigator_resolve_identity.html +++ b/dom/base/test/test_navigator_resolve_identity.html @@ -7,22 +7,39 @@ https://bugzilla.mozilla.org/show_bug.cg <meta charset="utf-8"> <title>Test for Bug 985827</title> <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script> <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> <script type="application/javascript"> /** Test for Bug 985827 **/ - // Test WebIDL NavigatorProperty objects - var x = navigator.mozContacts; - is(typeof x, "object", "Should have a mozContacts object"); - delete navigator.mozContacts; - var y = navigator.mozContacts; - is(x, y, "Should have gotten the same mozContacts object again"); + function test() { + var is = parent.is; + + // Test WebIDL NavigatorProperty objects + var x = navigator.mozContacts; + is(typeof x, "object", "Should have a mozContacts object"); + delete navigator.mozContacts; + var y = navigator.mozContacts; + is(x, y, "Should have gotten the same mozContacts object again"); + } + + SimpleTest.waitForExplicitFinish(); + + SpecialPowers.pushPermissions([ + {type: "contacts-read", allow: true, context: document}, + {type: "contacts-write", allow: true, context: document}, + {type: "contacts-create", allow: true, context: document}, + ], function() { + var iframe = document.createElement("iframe"); + iframe.src = "data:text/html,<script>(" + escape(test.toString()) + ")();</scr" + "ipt>"; + document.body.appendChild(iframe); + iframe.onload = function() { SimpleTest.finish(); }; + }); </script> </head> <body> <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=985827">Mozilla Bug 985827</a> <p id="display"></p> <div id="content" style="display: none">
--- a/dom/base/test/test_navigator_resolve_identity_xrays.xul +++ b/dom/base/test/test_navigator_resolve_identity_xrays.xul @@ -4,36 +4,55 @@ <!-- https://bugzilla.mozilla.org/show_bug.cgi?id=985827 --> <window title="Mozilla Bug 985827" xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/> - <iframe id="t"></iframe> - <!-- test results are displayed in the html:body --> <body xmlns="http://www.w3.org/1999/xhtml"> <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=985827" target="_blank">Mozilla Bug 985827</a> + <iframe id="t"></iframe> </body> <!-- test code goes here --> <script type="application/javascript"> <![CDATA[ /** Test for Bug 985827 **/ SimpleTest.waitForExplicitFinish(); + + Components.utils.import("resource://gre/modules/Services.jsm"); + addLoadEvent(function() { - var nav = $("t").contentWindow.navigator; - ok(Components.utils.isXrayWrapper(nav), "Should have an Xray here"); + var iframe = document.getElementById("t"); + + Services.perms.addFromPrincipal(iframe.contentDocument.nodePrincipal, + "contacts-read", + Services.perms.ALLOW_ACTION); + Services.perms.addFromPrincipal(iframe.contentDocument.nodePrincipal, + "contacts-write", + Services.perms.ALLOW_ACTION); + Services.perms.addFromPrincipal(iframe.contentDocument.nodePrincipal, + "contacts-create", + Services.perms.ALLOW_ACTION); - // Test WebIDL NavigatorProperty objects - is(typeof nav.mozContacts, "object", "Should have a mozContacts object"); - is(nav.mozContacts, nav.mozContacts, - "Should have gotten the same mozContacts object again"); + var dir = "chrome://mochitests/content/chrome/dom/base/test/"; + iframe.src = dir + "file_navigator_resolve_identity_xrays.xul"; + iframe.onload = function() { finish(); }; - SimpleTest.finish(); + function finish() { + Services.perms.removeFromPrincipal(document.nodePrincipal, + "contacts-read"); + Services.perms.removeFromPrincipal(document.nodePrincipal, + "contacts-write"); + Services.perms.removeFromPrincipal(document.nodePrincipal, + "contacts-create"); + SimpleTest.finish(); + } }); + ]]> </script> </window>
new file mode 100644 --- /dev/null +++ b/dom/bindings/test/file_bug707564-2.html @@ -0,0 +1,45 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=707564 +--> +<head> + <meta charset="utf-8"> + <title>Test for Bug 707564</title> + <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> + <script type="application/javascript"> + + /** Test for Bug 707564 **/ + var ok = parent.ok; + var isnot = parent.isnot; + + addLoadEvent(function() { + var props = Object.getOwnPropertyNames(frames[0].navigator); + isnot(props.indexOf("mozContacts"), -1, + "Should enumerate a mozContacts property on navigator"); + + // Now enumerate a different navigator object + var found = false; + for (var name in frames[1].navigator) { + if (name == "mozContacts") { + found = true; + } + } + ok(found, "Should enumerate a mozContacts property on navigator via for...in"); + parent.SimpleTest.finish(); + }); + + </script> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=707564">Mozilla Bug 707564</a> +<p id="display"></p> +<div id="content" style="display: none"> +<iframe></iframe> +<iframe></iframe> +</div> +<pre id="test"> +</pre> +</body> +</html>
--- a/dom/bindings/test/mochitest.ini +++ b/dom/bindings/test/mochitest.ini @@ -1,12 +1,13 @@ [DEFAULT] support-files = file_InstanceOf.html file_bug707564.html + file_bug707564-2.html file_bug775543.html file_document_location_set_via_xray.html file_dom_xrays.html file_proxies_via_xray.html forOf_iframe.html [test_async_stacks.html] [test_ByteString.html]
--- a/dom/bindings/test/test_bug707564-chrome.html +++ b/dom/bindings/test/test_bug707564-chrome.html @@ -9,17 +9,17 @@ https://bugzilla.mozilla.org/show_bug.cg <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"/> </head> <body> <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=707564">Mozilla Bug 707564</a> <p id="display"></p> <div id="content" style="display: none"> <iframe id="t1" src="http://example.org/tests/dom/bindings/test/file_bug707564.html"></iframe> -<iframe id="t2" src="http://example.org/tests/dom/bindings/test/file_bug707564.html"></iframe> +<iframe id="t2"></iframe> </div> <pre id="test"> <script type="application/javascript"> /** Test for Bug 775543 **/ function test() { var nav = document.getElementById("t1").contentWindow.navigator; @@ -38,15 +38,29 @@ function test() found = true; } } ok(found, "Should enumerate a mozContacts property on navigator xray via for...in"); SimpleTest.finish(); } -addLoadEvent(test); +onload = test; +onload = function() { + var iframe1 = document.getElementById("t1"); + SpecialPowers.pushPermissions([ + {type: "contacts-read", allow: true, context: iframe1.contentDocument}, + {type: "contacts-write", allow: true, context: iframe1.contentDocument}, + {type: "contacts-create", allow: true, context: iframe1.contentDocument}, + ], function() { + iframe1.src = "http://example.org/tests/dom/bindings/test/file_bug707564.html"; + iframe1.onload = function() { + var iframe2 = document.getElementById("t2"); + iframe2.src = "http://example.org/tests/dom/bindings/test/file_bug707564.html"; + iframe2.onload = test; + }; + }); +}; -SimpleTest.waitForExplicitFinish(); </script> </pre> </body> </html>
--- a/dom/bindings/test/test_bug707564.html +++ b/dom/bindings/test/test_bug707564.html @@ -1,43 +1,29 @@ <!DOCTYPE HTML> <html> -<!-- -https://bugzilla.mozilla.org/show_bug.cgi?id=707564 ---> <head> - <meta charset="utf-8"> - <title>Test for Bug 707564</title> <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script> <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> - <script type="application/javascript"> - - /** Test for Bug 707564 **/ - SimpleTest.waitForExplicitFinish(); - - addLoadEvent(function() { - var props = Object.getOwnPropertyNames(frames[0].navigator); - isnot(props.indexOf("mozContacts"), -1, - "Should enumerate a mozContacts property on navigator"); - - // Now enumerate a different navigator object - var found = false; - for (var name in frames[1].navigator) { - if (name == "mozContacts") { - found = true; - } - } - ok(found, "Should enumerate a mozContacts property on navigator via for...in"); - SimpleTest.finish(); - }); - </script> </head> <body> -<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=707564">Mozilla Bug 707564</a> -<p id="display"></p> -<div id="content" style="display: none"> <iframe></iframe> -<iframe></iframe> -</div> <pre id="test"> +<script type="application/javascript"> + +function run_tests() { + var iframe = document.querySelector("iframe"); + iframe.src = "file_bug707564-2.html"; +} + +SimpleTest.waitForExplicitFinish(); +onload = function() { + SpecialPowers.pushPermissions([ + {type: "contacts-read", allow: true, context: document}, + {type: "contacts-write", allow: true, context: document}, + {type: "contacts-create", allow: true, context: document}, + ], run_tests); +}; + +</script> </pre> </body> </html>
new file mode 100644 --- /dev/null +++ b/dom/contacts/tests/file_contacts_basics.html @@ -0,0 +1,787 @@ +<!DOCTYPE html> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=674720 +--> +<head> + <title>Test for Bug 674720 WebContacts</title> + <script type="text/javascript" src="/MochiKit/MochiKit.js"></script> + <script type="text/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=674720">Mozilla Bug 674720</a> +<p id="display"></p> +<div id="content" style="display: none"> + +</div> +<pre id="test"> +<script type="text/javascript;version=1.8" src="http://mochi.test:8888/tests/dom/contacts/tests/shared.js"></script> +<script class="testbody" type="text/javascript"> +"use strict"; + +var ok = parent.ok; +var is = parent.is; + +var initialRev; + +function checkRevision(revision, msg, then) { + var revReq = mozContacts.getRevision(); + revReq.onsuccess = function(e) { + is(e.target.result, initialRev+revision, msg); + then(); + }; + // The revision function isn't supported on Android so treat on failure as success + if (isAndroid) { + revReq.onerror = function(e) { + then(); + }; + } else { + revReq.onerror = onFailure; + } +} + +var req; + +var steps = [ + function() { + req = mozContacts.getRevision(); + req.onsuccess = function(e) { + initialRev = e.target.result; + next(); + }; + + // Android does not support the revision function. Treat errors as success. + if (isAndroid) { + req.onerror = function(e) { + initialRev = 0; + next(); + }; + } else { + req.onerror = onFailure; + } + }, + function () { + ok(true, "Deleting database"); + checkRevision(0, "Initial revision is 0", function() { + req = mozContacts.clear(); + req.onsuccess = function () { + ok(true, "Deleted the database"); + checkCount(0, "No contacts after clear", function() { + checkRevision(1, "Revision was incremented on clear", next); + }); + }; + req.onerror = onFailure; + }); + }, + function () { + ok(true, "Retrieving all contacts"); + req = mozContacts.find(defaultOptions); + req.onsuccess = function () { + is(req.result.length, 0, "Empty database."); + checkRevision(1, "Revision was not incremented on find", next); + }; + req.onerror = onFailure; + }, + function () { + ok(true, "Adding empty contact"); + createResult1 = new mozContact({}); + req = navigator.mozContacts.save(createResult1); + req.onsuccess = function () { + ok(createResult1.id, "The contact now has an ID."); + sample_id1 = createResult1.id; + checkCount(1, "1 contact after adding empty contact", function() { + checkRevision(2, "Revision was incremented on save", next); + }); + }; + req.onerror = onFailure; + }, + function () { + ok(true, "Retrieving all contacts"); + req = mozContacts.find(defaultOptions); + req.onsuccess = function () { + is(req.result.length, 1, "One contact."); + findResult1 = req.result[0]; + next(); + }; + req.onerror = onFailure; + }, + function () { + ok(true, "Deleting empty contact"); + req = navigator.mozContacts.remove(findResult1); + req.onsuccess = function () { + var req2 = mozContacts.find(defaultOptions); + req2.onsuccess = function () { + is(req2.result.length, 0, "Empty Database."); + clearTemps(); + checkRevision(3, "Revision was incremented on remove", next); + } + req2.onerror = onFailure; + } + req.onerror = onFailure; + }, + function () { + ok(true, "Adding a new contact1"); + createResult1 = new mozContact(properties1); + + mozContacts.oncontactchange = function(event) { + is(event.contactID, createResult1.id, "Same contactID"); + is(event.reason, "create", "Same reason"); + next(); + } + + req = navigator.mozContacts.save(createResult1); + req.onsuccess = function () { + ok(createResult1.id, "The contact now has an ID."); + sample_id1 = createResult1.id; + checkContacts(createResult1, properties1); + }; + req.onerror = onFailure; + }, + function () { + ok(true, "Retrieving by substring 1"); + var options = {filterBy: ["givenName"], + filterOp: "startsWith", + filterValue: properties1.givenName[1].substring(0,3)}; + req = mozContacts.find(options); + req.onsuccess = function () { + is(req.result.length, 1, "Found exactly 1 contact."); + findResult1 = req.result[0]; + ok(findResult1.id == sample_id1, "Same ID"); + checkContacts(createResult1, properties1); + // Some manual testing. Testint the testfunctions + // tel: [{type: ["work"], value: "123456", carrier: "testCarrier"} , {type: ["home", "fax"], value: "+55 (31) 9876-3456"}], + is(findResult1.tel[0].carrier, "testCarrier", "Same Carrier"); + is(String(findResult1.tel[0].type), "work", "Same type"); + is(findResult1.tel[0].value, "123456", "Same Value"); + is(findResult1.tel[1].type[1], "fax", "Same type"); + is(findResult1.tel[1].value, "+55 (31) 9876-3456", "Same Value"); + + is(findResult1.adr[0].countryName, "country 1", "Same country"); + + // email: [{type: ["work"], value: "x@y.com"}] + is(String(findResult1.email[0].type), "work", "Same Type"); + is(findResult1.email[0].value, "x@y.com", "Same Value"); + next(); + }; + req.onerror = onFailure; + }, + function () { + ok(true, "Searching for exact email"); + var options = {filterBy: ["email"], + filterOp: "equals", + filterValue: properties1.email[0].value}; + req = mozContacts.find(options); + req.onsuccess = function () { + is(req.result.length, 1, "Found exactly 1 contact."); + findResult1 = req.result[0]; + ok(findResult1.id == sample_id1, "Same ID"); + checkContacts(findResult1, createResult1); + next(); + }; + req.onerror = onFailure; + }, + function () { + ok(true, "Retrieving by substring and update"); + mozContacts.oncontactchange = function(event) { + is(event.contactID, findResult1.id, "Same contactID"); + is(event.reason, "update", "Same reason"); + } + var options = {filterBy: ["givenName"], + filterOp: "startsWith", + filterValue: properties1.givenName[0].substring(0,3)}; + req = mozContacts.find(options); + req.onsuccess = function () { + is(req.result.length, 1, "Found exactly 1 contact."); + findResult1 = req.result[0]; + findResult1.jobTitle = ["new Job"]; + ok(findResult1.id == sample_id1, "Same ID"); + checkContacts(createResult1, properties1); + next(); + }; + req.onerror = onFailure; + }, + function () { + ok(true, "Adding a new contact"); + mozContacts.oncontactchange = function(event) { + is(event.contactID, createResult2.id, "Same contactID"); + is(event.reason, "create", "Same reason"); + } + createResult2 = new mozContact({name: ["newName"]}); + req = navigator.mozContacts.save(createResult2); + req.onsuccess = function () { + ok(createResult2.id, "The contact now has an ID."); + next(); + }; + req.onerror = onFailure; + }, + function () { + ok(true, "Retrieving by substring 2"); + var options = {filterBy: ["givenName"], + filterOp: "startsWith", + filterValue: properties1.givenName[0].substring(0,3)}; + req = mozContacts.find(options); + req.onsuccess = function () { + is(req.result.length, 1, "Found exactly 1 contact."); + findResult1 = req.result[0]; + checkContacts(createResult1, findResult1); + next(); + }; + req.onerror = onFailure; + }, + function() { + ok(true, "Retrieving by name equality 1"); + var options = {filterBy: ["name"], + filterOp: "equals", + filterValue: properties1.name[0]}; + req = mozContacts.find(options); + req.onsuccess = function () { + is(req.result.length, 1, "Found exactly 1 contact."); + findResult1 = req.result[0]; + checkContacts(createResult1, findResult1); + next(); + }; + req.onerror = onFailure; + }, + function() { + ok(true, "Retrieving by name equality 2"); + var options = {filterBy: ["name"], + filterOp: "equals", + filterValue: properties1.name[1]}; + req = mozContacts.find(options); + req.onsuccess = function () { + is(req.result.length, 1, "Found exactly 1 contact."); + findResult1 = req.result[0]; + checkContacts(createResult1, findResult1); + next(); + }; + req.onerror = onFailure; + }, + function() { + ok(true, "Retrieving by name substring 1"); + var options = {filterBy: ["name"], + filterOp: "startsWith", + filterValue: properties1.name[0].substring(0,3).toLowerCase()}; + req = mozContacts.find(options); + req.onsuccess = function () { + is(req.result.length, 1, "Found exactly 1 contact."); + findResult1 = req.result[0]; + checkContacts(createResult1, findResult1); + next(); + }; + req.onerror = onFailure; + }, + function() { + ok(true, "Retrieving by name substring 2"); + var options = {filterBy: ["name"], + filterOp: "startsWith", + filterValue: properties1.name[1].substring(0,3).toLowerCase()}; + req = mozContacts.find(options); + req.onsuccess = function () { + is(req.result.length, 1, "Found exactly 1 contact."); + findResult1 = req.result[0]; + checkContacts(createResult1, findResult1); + next(); + }; + req.onerror = onFailure; + }, + function () { + ok(true, "Remove contact1"); + mozContacts.oncontactchange = function(event) { + is(event.contactID, createResult1.id, "Same contactID"); + is(event.reason, "remove", "Same reason"); + } + req = navigator.mozContacts.remove(createResult1); + req.onsuccess = function () { + next(); + }; + req.onerror = onFailure; + }, + function () { + ok(true, "Retrieving by substring 3"); + var options = {filterBy: ["givenName"], + filterOp: "startsWith", + filterValue: properties1.givenName[1].substring(0,3)}; + req = mozContacts.find(options); + req.onsuccess = function () { + is(req.result.length, 0, "Found no contact."); + next(); + }; + req.onerror = onFailure; + }, + function () { + ok(true, "Remove contact2"); + mozContacts.oncontactchange = function(event) { + is(event.contactID, createResult2.id, "Same contactID"); + is(event.reason, "remove", "Same reason"); + } + req = navigator.mozContacts.remove(createResult2); + req.onsuccess = function () { + next(); + }; + req.onerror = onFailure; + }, + function () { + ok(true, "Retrieving by substring 4"); + var options = {filterBy: ["givenName"], + filterOp: "startsWith", + filterValue: properties1.givenName[1].substring(0,3)}; + req = mozContacts.find(options); + req.onsuccess = function () { + is(req.result.length, 0, "Found no contact."); + next(); + }; + req.onerror = onFailure; + }, + function () { + ok(true, "Deleting database"); + mozContacts.oncontactchange = function(event) { + is(event.contactID, "undefined", "Same contactID"); + is(event.reason, "remove", "Same reason"); + } + req = mozContacts.clear(); + req.onsuccess = function () { + ok(true, "Deleted the database"); + next(); + }; + req.onerror = onFailure; + }, + function () { + ok(true, "Adding a new contact with properties1"); + createResult1 = new mozContact(properties1); + mozContacts.oncontactchange = null; + req = navigator.mozContacts.save(createResult1); + req.onsuccess = function () { + ok(createResult1.id, "The contact now has an ID."); + sample_id1 = createResult1.id; + checkContacts(createResult1, properties1); + next(); + }; + req.onerror = onFailure; + }, + function () { + ok(true, "Retrieving by substring tel1"); + var options = {filterBy: ["tel"], + filterOp: "contains", + filterValue: properties1.tel[1].value.substring(2,5)}; + req = mozContacts.find(options); + req.onsuccess = function () { + is(req.result.length, 1, "Found exactly 1 contact."); + findResult1 = req.result[0]; + ok(findResult1.id == sample_id1, "Same ID"); + checkContacts(createResult1, properties1); + next(); + }; + req.onerror = onFailure; + }, + function () { + ok(true, "Retrieving by tel exact"); + var options = {filterBy: ["tel"], + filterOp: "equals", + filterValue: "+55 319 8 7 6 3456"}; + req = mozContacts.find(options); + req.onsuccess = function () { + is(req.result.length, 1, "Found exactly 1 contact."); + findResult1 = req.result[0]; + ok(findResult1.id == sample_id1, "Same ID"); + checkContacts(createResult1, properties1); + next(); + }; + req.onerror = onFailure; + }, + function () { + ok(true, "Retrieving by tel exact with substring"); + var options = {filterBy: ["tel"], + filterOp: "equals", + filterValue: "3456"}; + req = mozContacts.find(options); + req.onsuccess = function () { + is(req.result.length, 0, "Found no contacts."); + next(); + }; + req.onerror = onFailure; + }, + function () { + ok(true, "Retrieving by tel exact with substring"); + var options = {filterBy: ["tel"], + filterOp: "equals", + filterValue: "+55 (31)"}; + req = mozContacts.find(options); + req.onsuccess = function () { + is(req.result.length, 0, "Found no contacts."); + next(); + }; + req.onerror = onFailure; + }, + function () { + ok(true, "Retrieving by tel match national number"); + var options = {filterBy: ["tel"], + filterOp: "match", + filterValue: "3198763456"}; + req = mozContacts.find(options); + req.onsuccess = function () { + is(req.result.length, 1, "Found exactly 1 contact."); + findResult1 = req.result[0]; + ok(findResult1.id == sample_id1, "Same ID"); + checkContacts(createResult1, properties1); + next(); + }; + req.onerror = onFailure; + }, + function () { + ok(true, "Retrieving by tel match national format"); + var options = {filterBy: ["tel"], + filterOp: "match", + filterValue: "0451 491934"}; + req = mozContacts.find(options); + req.onsuccess = function () { + is(req.result.length, 1, "Found exactly 1 contact."); + findResult1 = req.result[0]; + ok(findResult1.id == sample_id1, "Same ID"); + checkContacts(createResult1, properties1); + next(); + }; + req.onerror = onFailure; + }, + function () { + ok(true, "Retrieving by tel match entered number"); + var options = {filterBy: ["tel"], + filterOp: "match", + filterValue: "123456"}; + req = mozContacts.find(options); + req.onsuccess = function () { + is(req.result.length, 1, "Found exactly 1 contact."); + findResult1 = req.result[0]; + ok(findResult1.id == sample_id1, "Same ID"); + checkContacts(createResult1, properties1); + next(); + }; + req.onerror = onFailure; + }, + function () { + ok(true, "Retrieving by tel match international number"); + var options = {filterBy: ["tel"], + filterOp: "match", + filterValue: "+55 31 98763456"}; + req = mozContacts.find(options); + req.onsuccess = function () { + is(req.result.length, 1, "Found exactly 1 contact."); + findResult1 = req.result[0]; + ok(findResult1.id == sample_id1, "Same ID"); + checkContacts(createResult1, properties1); + next(); + }; + req.onerror = onFailure; + }, + function () { + ok(true, "Retrieving by match with field other than tel"); + var options = {filterBy: ["givenName"], + filterOp: "match", + filterValue: "my friends call me 555-4040"}; + req = mozContacts.find(options); + req.onsuccess = onUnwantedSuccess; + req.onerror = function() { + ok(true, "Failed"); + next(); + } + }, + function () { + ok(true, "Retrieving by substring tel2"); + var options = {filterBy: ["tel"], + filterOp: "startsWith", + filterValue: "9876"}; + req = mozContacts.find(options); + req.onsuccess = function () { + is(req.result.length, 1, "Found exactly 1 contact."); + findResult1 = req.result[0]; + ok(findResult1.id == sample_id1, "Same ID"); + checkContacts(createResult1, properties1); + next(); + }; + req.onerror = onFailure; + }, + function () { + ok(true, "Retrieving by substring tel3"); + var options = {filterBy: ["tel"], + filterOp: "startsWith", + filterValue: "98763456"}; + req = mozContacts.find(options); + req.onsuccess = function () { + is(req.result.length, 1, "Found exactly 1 contact."); + findResult1 = req.result[0]; + ok(findResult1.id == sample_id1, "Same ID"); + checkContacts(createResult1, properties1); + next(); + }; + req.onerror = onFailure; + }, + function () { + ok(true, "Retrieving by substring 5"); + var options = {filterBy: ["givenName"], + filterOp: "startsWith", + filterValue: properties1.givenName[0].substring(0,3)}; + req = mozContacts.find(options); + req.onsuccess = function () { + is(req.result.length, 1, "Found exactly 1 contact."); + findResult1 = req.result[0]; + ok(findResult1.id == sample_id1, "Same ID"); + checkContacts(createResult1, properties1); + next(); + }; + req.onerror = onFailure; + }, + function () { + ok(true, "Retrieving by substring 6"); + var options = {filterBy: ["familyName", "givenName"], + filterOp: "startsWith", + filterValue: properties1.givenName[0].substring(0,3)}; + req = mozContacts.find(options); + req.onsuccess = function () { + is(req.result.length, 1, "Found exactly 1 contact."); + findResult1 = req.result[0]; + ok(findResult1.id == sample_id1, "Same ID"); + checkContacts(createResult1, properties1); + next(); + }; + req.onerror = onFailure; + }, + function () { + ok(true, "Retrieving by substring3, Testing multi entry"); + var options = {filterBy: ["givenName", "familyName"], + filterOp: "startsWith", + filterValue: properties1.familyName[1].substring(0,3).toLowerCase()}; + req = mozContacts.find(options); + req.onsuccess = function () { + is(req.result.length, 1, "Found exactly 1 contact."); + findResult1 = req.result[0]; + ok(findResult1.id == sample_id1, "Same ID"); + checkContacts(createResult1, properties1); + next(); + }; + req.onerror = onFailure; + }, + function () { + ok(true, "Retrieving all contacts"); + req = mozContacts.find(defaultOptions); + req.onsuccess = function() { + is(req.result.length, 1, "Found exactly 1 contact."); + findResult1 = req.result[0]; + ok(findResult1.id == sample_id1, "Same ID"); + checkContacts(createResult1, findResult1); + if (!isAndroid) { + ok(findResult1.updated, "Has updated field"); + ok(findResult1.published, "Has published field"); + } + next(); + } + req.onerror = onFailure; + }, + function () { + ok(true, "Modifying contact1"); + if (!findResult1) { + SpecialPowers.executeSoon(next); + } else { + findResult1.impp = properties1.impp = [{value:"phil impp"}]; + req = navigator.mozContacts.save(findResult1); + req.onsuccess = function () { + var req2 = mozContacts.find(defaultOptions); + req2.onsuccess = function() { + is(req2.result.length, 1, "Found exactly 1 contact."); + findResult2 = req2.result[0]; + ok(findResult2.id == sample_id1, "Same ID"); + checkContacts(findResult2, properties1); + is(findResult2.impp.length, 1, "Found exactly 1 IMS info."); + next(); + }; + req2.onerror = onFailure; + }; + req.onerror = onFailure; + } + }, + function() { + // Android does not support published/updated fields. Skip this. + if (isAndroid) { + next(); + return; + } + + ok(true, "Saving old contact, should abort!"); + req = mozContacts.save(createResult1); + req.onsuccess = onUnwantedSuccess; + req.onerror = function() { ok(true, "Successfully declined updating old contact!"); next(); }; + }, + function () { + ok(true, "Retrieving a specific contact by ID"); + var options = {filterBy: ["id"], + filterOp: "equals", + filterValue: sample_id1}; + req = mozContacts.find(options); + req.onsuccess = function () { + is(req.result.length, 1, "Found exactly 1 contact."); + findResult1 = req.result[0]; + ok(findResult1.id == sample_id1, "Same ID"); + checkContacts(findResult1, properties1); + next(); + }; + req.onerror = onFailure; + }, + function () { + ok(true, "Retrieving a specific contact by givenName"); + var options = {filterBy: ["givenName"], + filterOp: "equals", + filterValue: properties1.givenName[0]}; + req = mozContacts.find(options); + req.onsuccess = function () { + is(req.result.length, 1, "Found exactly 1 contact."); + findResult1 = req.result[0]; + ok(findResult1.id == sample_id1, "Same ID"); + checkContacts(findResult1, properties1); + next(); + } + req.onerror = onFailure; + }, + function () { + ok(true, "Modifying contact2"); + if (!findResult1) { + SpecialPowers.executeSoon(next); + } else { + findResult1.impp = properties1.impp = [{value: "phil impp"}]; + req = mozContacts.save(findResult1); + req.onsuccess = function () { + var req2 = mozContacts.find(defaultOptions); + req2.onsuccess = function () { + is(req2.result.length, 1, "Found exactly 1 contact."); + findResult1 = req2.result[0]; + ok(findResult1.id == sample_id1, "Same ID"); + checkContacts(findResult1, properties1); + is(findResult1.impp.length, 1, "Found exactly 1 IMS info."); + next(); + } + req2.onerror = onFailure; + }; + req.onerror = onFailure; + } + }, + function () { + ok(true, "Searching contacts by query"); + var options = {filterBy: ["givenName", "email"], + filterOp: "startsWith", + filterValue: properties1.givenName[0].substring(0,4)}; + req = mozContacts.find(options); + req.onsuccess = function () { + is(req.result.length, 1, "Found exactly 1 contact."); + findResult1 = req.result[0]; + ok(findResult1.id == sample_id1, "Same ID"); + checkContacts(findResult1, properties1); + next(); + }; + req.onerror = onFailure; + }, + function () { + ok(true, "Searching contacts by query"); + var options = {filterBy: ["givenName", "email"], + filterOp: "startsWith", + filterValue: properties1.givenName[0]}; + req = mozContacts.find(options); + req.onsuccess = function () { + is(req.result.length, 1, "Found exactly 1 contact."); + findResult1 = req.result[0]; + ok(findResult1.id == sample_id1, "Same ID"); + checkContacts(findResult1, properties1); + next(); + }; + req.onerror = onFailure; + }, + function () { + ok(true, "Searching contacts with multiple indices"); + var options = {filterBy: ["email", "givenName"], + filterOp: "equals", + filterValue: properties1.givenName[1]}; + req = mozContacts.find(options); + req.onsuccess = function () { + is(req.result.length, 1, "Found exactly 1 contact."); + findResult1 = req.result[0]; + ok(findResult1.id == sample_id1, "Same ID"); + checkContacts(findResult1, properties1); + next(); + }; + req.onerror = onFailure; + }, + function () { + ok(true, "Modifying contact3"); + if (!findResult1) { + SpecialPowers.executeSoon(next); + } else { + findResult1.email = [{value: properties1.nickname}]; + findResult1.nickname = ["TEST"]; + var newContact = new mozContact(findResult1); + req = mozContacts.save(newContact); + req.onsuccess = function () { + var options = {filterBy: ["email", "givenName"], + filterOp: "startsWith", + filterValue: properties1.givenName[0]}; + // One contact has it in nickname and the other in email + var req2 = mozContacts.find(options); + req2.onsuccess = function () { + is(req2.result.length, 2, "Found exactly 2 contacts."); + ok(req2.result[0].id != req2.result[1].id, "Different ID"); + next(); + } + req2.onerror = onFailure; + }; + req.onerror = onFailure; + } + }, + function () { + ok(true, "Deleting contact" + findResult1); + req = mozContacts.remove(findResult1); + req.onsuccess = function () { + var req2 = mozContacts.find(defaultOptions); + req2.onsuccess = function () { + is(req2.result.length, 1, "One contact left."); + findResult1 = req2.result[0]; + next(); + } + req2.onerror = onFailure; + } + req.onerror = onFailure; + }, + function () { + ok(true, "Deleting database"); + req = mozContacts.remove(findResult1); + req.onsuccess = function () { + clearTemps(); + next(); + }; + req.onerror = onFailure; + }, + function() { + ok(true, "Test JSON.stringify output for mozContact objects"); + var json = JSON.parse(JSON.stringify(new mozContact(properties1))); + checkContacts(json, properties1); + next(); + }, + function() { + ok(true, "Test slice"); + var c = new mozContact(); + c.email = [{ type: ["foo"], value: "bar@baz" }] + var arr = c.email; + is(arr[0].value, "bar@baz", "Should have the right value"); + arr = arr.slice(); + is(arr[0].value, "bar@baz", "Should have the right value after slicing"); + next(); + }, + function () { + ok(true, "all done!\n"); + clearTemps(); + + parent.SimpleTest.finish(); + } +]; + +start_tests(); +</script> +</pre> +</body> +</html>
new file mode 100644 --- /dev/null +++ b/dom/contacts/tests/file_contacts_basics2.html @@ -0,0 +1,1153 @@ +<!DOCTYPE html> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=674720 +--> +<head> + <title>Test for Bug 674720 WebContacts</title> + <script type="text/javascript" src="/MochiKit/MochiKit.js"></script> + <script type="text/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=674720">Mozilla Bug 674720</a> +<p id="display"></p> +<div id="content" style="display: none"> + +</div> +<pre id="test"> +<script type="text/javascript;version=1.8" src="http://mochi.test:8888/tests/dom/contacts/tests/shared.js"></script> +<script class="testbody" type="text/javascript"> +"use strict"; + +var ok = parent.ok; +var is = parent.is; +var isnot = parent.isnot; + +var req; + +var steps = [ + function () { + ok(true, "Adding a new contact"); + createResult1 = new mozContact(properties1); + req = mozContacts.save(createResult1) + req.onsuccess = function () { + ok(createResult1.id, "The contact now has an ID."); + sample_id1 = createResult1.id; + next(); + } + req.onerror = onFailure; + }, + function () { + ok(true, "Adding a new contact2"); + createResult2 = new mozContact(properties2); + req = mozContacts.save(createResult2); + req.onsuccess = function () { + ok(createResult2.id, "The contact now has an ID."); + sample_id2 = createResult2.id; + next(); + }; + req.onerror = onFailure; + }, + function () { + ok(true, "Retrieving all contacts"); + req = mozContacts.find({sortBy: "familyName"}); + req.onsuccess = function () { + is(req.result.length, 2, "Found exactly 2 contact."); + checkContacts(req.result[1], properties1); + next(); + } + req.onerror = onFailure; + }, + function () { + console.log("Searching contacts by query1"); + var options = {filterBy: ["givenName", "email"], + filterOp: "startsWith", + filterValue: properties1.givenName[0].substring(0, 4)} + req = mozContacts.find(options) + req.onsuccess = function () { + is(req.result.length, 1, "Found exactly 1 contact."); + findResult1 = req.result[0]; + ok(findResult1.id == sample_id1, "Same ID"); + checkContacts(findResult1, createResult1); + next(); + } + req.onerror = onFailure; + }, + function () { + ok(true, "Searching contacts by query2"); + var options = {filterBy: ["givenName", "email"], + filterOp: "startsWith", + filterValue: properties2.givenName[0].substring(0, 4)}; + req = mozContacts.find(options); + req.onsuccess = function () { + is(req.result.length, 1, "Found exactly 1 contact."); + findResult1 = req.result[0]; + is(findResult1.adr.length, 2, "Adr length 2"); + checkContacts(findResult1, createResult2); + next(); + } + req.onerror = onFailure; + }, + function () { + ok(true, "Searching contacts by tel"); + var options = {filterBy: ["tel"], + filterOp: "contains", + filterValue: properties2.tel[0].value.substring(3, 7)}; + req = mozContacts.find(options); + req.onsuccess = function () { + is(req.result.length, 1, "Found exactly 1 contact."); + findResult1 = req.result[0]; + ok(findResult1.id == sample_id2, "Same ID"); + checkContacts(findResult1, createResult2); + next(); + } + req.onerror = onFailure; + }, + function () { + ok(true, "Searching contacts by email"); + var options = {filterBy: ["email"], + filterOp: "startsWith", + filterValue: properties2.email[0].value.substring(0, 4)}; + req = mozContacts.find(options); + req.onsuccess = function () { + is(req.result.length, 1, "Found exactly 1 contact."); + findResult1 = req.result[0]; + ok(findResult1.id == sample_id2, "Same ID"); + checkContacts(findResult1, createResult2); + next(); + } + req.onerror = onFailure; + }, + function () { + ok(true, "Deleting database"); + req = mozContacts.clear(); + req.onsuccess = function () { + next(); + } + req.onerror = onFailure; + }, + function () { + ok(true, "Adding 20 contacts"); + for (var i=0; i<19; i++) { + createResult1 = new mozContact(properties1); + req = mozContacts.save(createResult1); + req.onsuccess = function () { + ok(createResult1.id, "The contact now has an ID."); + }; + req.onerror = onFailure; + }; + createResult1 = new mozContact(properties1); + req = mozContacts.save(createResult1); + req.onsuccess = function () { + ok(createResult1.id, "The contact now has an ID."); + checkStrArray(createResult1.name, properties1.name, "Same Name"); + checkCount(20, "20 contacts in DB", next); + }; + req.onerror = onFailure; + }, + function () { + ok(true, "Retrieving all contacts"); + req = mozContacts.find(defaultOptions); + req.onsuccess = function () { + is(req.result.length, 20, "20 Entries."); + next(); + } + req.onerror = onFailure; + }, + function () { + ok(true, "Retrieving all contacts with limit 10"); + var options = { filterLimit: 10 }; + req = mozContacts.find(options); + req.onsuccess = function () { + is(req.result.length, 10, "10 Entries."); + next(); + } + req.onerror = onFailure; + }, + function () { + ok(true, "Retrieving all contacts with limit 10 and sorted"); + var options = { filterLimit: 10, + sortBy: 'FamilyName', + sortOrder: 'descending' }; + req = mozContacts.find(options); + req.onsuccess = function () { + is(req.result.length, 10, "10 Entries."); + next(); + } + req.onerror = onFailure; + }, + function () { + ok(true, "Retrieving all contacts2"); + var options = {filterBy: ["givenName"], + filterOp: "startsWith", + filterValue: properties1.givenName[0].substring(0, 4)}; + req = mozContacts.find(options); + req.onsuccess = function () { + is(req.result.length, 20, "20 Entries."); + checkContacts(createResult1, req.result[19]); + next(); + } + req.onerror = onFailure; + }, + function () { + ok(true, "Retrieving all contacts3"); + var options = {filterBy: ["givenName", "tel", "email"], + filterOp: "startsWith", + filterValue: properties1.givenName[0].substring(0, 4)}; + req = mozContacts.find(options); + req.onsuccess = function () { + is(req.result.length, 20, "20 Entries."); + checkContacts(createResult1, req.result[10]); + next(); + } + req.onerror = onFailure; + }, + function () { + ok(true, "Deleting database"); + req = mozContacts.clear(); + req.onsuccess = function () { + next(); + } + req.onerror = onFailure; + }, + function () { + ok(true, "Testing clone contact"); + createResult1 = new mozContact(properties1); + req = mozContacts.save(createResult1); + req.onsuccess = function () { + ok(createResult1.id, "The contact now has an ID."); + checkStrArray(createResult1.name, properties1.name, "Same Name"); + next(); + } + req.onerror = onFailure; + }, + function() { + ok(true, "Testing clone contact2"); + var cloned = new mozContact(createResult1); + ok(cloned.id != createResult1.id, "Cloned contact has new ID"); + cloned.email = [{value: "new email!"}]; + cloned.givenName = ["Tom"]; + req = mozContacts.save(cloned); + req.onsuccess = function () { + ok(cloned.id, "The contact now has an ID."); + is(cloned.email[0].value, "new email!", "Same Email"); + isnot(createResult1.email[0].value, cloned.email[0].value, "Clone has different email"); + is(String(cloned.givenName), "Tom", "New Name"); + next(); + } + req.onerror = onFailure; + }, + function () { + ok(true, "Retrieving all contacts"); + var options = {filterBy: ["givenName"], + filterOp: "startsWith", + filterValue: properties2.givenName[0].substring(0, 4)}; + req = mozContacts.find(defaultOptions); + req.onsuccess = function () { + is(req.result.length, 2, "2 Entries."); + next(); + } + req.onerror = onFailure; + }, + function () { + ok(true, "Search with redundant fields should only return 1 contact"); + createResult1 = new mozContact({name: ["XXX"], + givenName: ["XXX"], + email: [{value: "XXX"}], + tel: [{value: "XXX"}] + }); + req = mozContacts.save(createResult1); + req.onsuccess = function() { + var options = {filterBy: ["givenName", "familyName"], + filterOp: "equals", + filterValue: "XXX"}; + var req2 = mozContacts.find(options); + req2.onsuccess = function() { + is(req2.result.length, 1, "1 Entry"); + next(); + } + req2.onerror = onFailure; + } + req.onerror = onFailure; + }, + function () { + ok(true, "Deleting database"); + req = mozContacts.clear() + req.onsuccess = function () { + ok(true, "Deleted the database"); + next(); + } + req.onerror = onFailure; + }, + function () { + ok(true, "Test sorting"); + createResult1 = new mozContact(c3); + req = navigator.mozContacts.save(createResult1); + req.onsuccess = function () { + ok(createResult1.id, "The contact now has an ID."); + checkContacts(c3, createResult1); + next(); + }; + req.onerror = onFailure; + }, + function () { + ok(true, "Test sorting"); + createResult1 = new mozContact(c2); + req = navigator.mozContacts.save(createResult1); + req.onsuccess = function () { + ok(createResult1.id, "The contact now has an ID."); + checkContacts(c2, createResult1); + next(); + }; + req.onerror = onFailure; + }, + function () { + ok(true, "Test sorting"); + createResult1 = new mozContact(c4); + req = navigator.mozContacts.save(createResult1); + req.onsuccess = function () { + ok(createResult1.id, "The contact now has an ID."); + checkContacts(c4, createResult1); + next(); + }; + req.onerror = onFailure; + }, + function () { + ok(true, "Test sorting"); + createResult1 = new mozContact(c1); + req = navigator.mozContacts.save(createResult1); + req.onsuccess = function () { + ok(createResult1.id, "The contact now has an ID."); + checkContacts(c1, createResult1); + next(); + }; + req.onerror = onFailure; + }, + function () { + ok(true, "Test sorting"); + var options = {sortBy: "familyName", + sortOrder: "ascending"}; + req = navigator.mozContacts.find(options); + req.onsuccess = function () { + is(req.result.length, 4, "4 results"); + checkContacts(req.result[0], c1); + checkContacts(req.result[1], c2); + checkContacts(req.result[2], c3); + checkContacts(req.result[3], c4); + next(); + }; + req.onerror = onFailure; + }, + function () { + ok(true, "Test sorting"); + var options = {sortBy: "familyName", + sortOrder: "descending"}; + req = navigator.mozContacts.find(options); + req.onsuccess = function () { + is(req.result.length, 4, "4 results"); + checkContacts(req.result[0], c4); + checkContacts(req.result[1], c3); + checkContacts(req.result[2], c2); + checkContacts(req.result[3], c1); + next(); + }; + req.onerror = onFailure; + }, + function () { + ok(true, "Test sorting"); + createResult1 = new mozContact(c5); + req = navigator.mozContacts.save(createResult1); + req.onsuccess = function () { + ok(createResult1.id, "The contact now has an ID."); + checkContacts(c5, createResult1); + next(); + }; + req.onerror = onFailure; + }, + function () { + ok(true, "Test sorting with empty string"); + var options = {sortBy: "familyName", + sortOrder: "ascending"}; + req = navigator.mozContacts.find(options); + req.onsuccess = function () { + is(req.result.length, 5, "5 results"); + checkContacts(req.result[0], c5); + checkContacts(req.result[1], c1); + checkContacts(req.result[2], c2); + checkContacts(req.result[3], c3); + checkContacts(req.result[4], c4); + next(); + }; + req.onerror = onFailure; + }, + function () { + ok(true, "Don't allow to add custom fields"); + createResult1 = new mozContact({givenName: ["customTest"], yyy: "XXX"}); + req = mozContacts.save(createResult1); + req.onsuccess = function() { + var options = {filterBy: ["givenName"], + filterOp: "equals", + filterValue: "customTest"}; + var req2 = mozContacts.find(options); + req2.onsuccess = function() { + is(req2.result.length, 1, "1 Entry"); + checkStrArray(req2.result[0].givenName, ["customTest"], "same name"); + ok(req2.result.yyy === undefined, "custom property undefined"); + next(); + } + req2.onerror = onFailure; + } + req.onerror = onFailure; + }, + function () { + ok(true, "Deleting database"); + req = mozContacts.clear() + req.onsuccess = function () { + ok(true, "Deleted the database"); + next(); + } + req.onerror = onFailure; + }, + function () { + ok(true, "Test sorting"); + createResult1 = new mozContact(c7); + req = navigator.mozContacts.save(createResult1); + req.onsuccess = function () { + ok(createResult1.id, "The contact now has an ID."); + checkContacts(c7, createResult1); + next(); + }; + req.onerror = onFailure; + }, + function () { + ok(true, "Test sorting"); + createResult1 = new mozContact(c6); + req = navigator.mozContacts.save(createResult1); + req.onsuccess = function () { + ok(createResult1.id, "The contact now has an ID."); + checkContacts(c6, createResult1); + next(); + }; + req.onerror = onFailure; + }, + function () { + ok(true, "Test sorting"); + createResult1 = new mozContact(c8); + req = navigator.mozContacts.save(createResult1); + req.onsuccess = function () { + ok(createResult1.id, "The contact now has an ID."); + checkContacts(c8, createResult1); + next(); + }; + req.onerror = onFailure; + }, + function () { + // Android does not support published/updated fields. Skip this. + if (isAndroid) { + next(); + return; + } + + ok(true, "Test sorting with published"); + var options = {sortBy: "familyName", + sortOrder: "descending"}; + req = navigator.mozContacts.find(options); + req.onsuccess = function () { + is(req.result.length, 3, "3 results"); + ok(req.result[0].published < req.result[1].published, "Right sorting order"); + ok(req.result[1].published < req.result[2].published, "Right sorting order"); + next(); + }; + req.onerror = onFailure; + }, + function () { + ok(true, "Deleting database"); + req = mozContacts.clear(); + req.onsuccess = function () { + ok(true, "Deleted the database"); + next(); + } + req.onerror = onFailure; + }, + function () { + ok(true, "Adding a new contact with properties2"); + createResult2 = new mozContact(properties2); + req = mozContacts.save(createResult2); + req.onsuccess = function () { + ok(createResult2.id, "The contact now has an ID."); + sample_id2 = createResult2.id; + next(); + }; + req.onerror = onFailure; + }, + function () { + ok(true, "Test category search with startsWith"); + var options = {filterBy: ["category"], + filterOp: "startsWith", + filterValue: properties2.category[0]}; + req = mozContacts.find(options); + req.onsuccess = function () { + is(req.result.length, 1, "1 Entry."); + checkContacts(req.result[0], createResult2); + next(); + } + req.onerror = onFailure; + }, + function () { + ok(true, "Test category search with equals"); + var options = {filterBy: ["category"], + filterOp: "equals", + filterValue: properties2.category[0]}; + req = mozContacts.find(options); + req.onsuccess = function () { + is(req.result.length, 1, "1 Entry."); + checkContacts(req.result[0], createResult2); + next(); + } + req.onerror = onFailure; + }, + function () { + ok(true, "Deleting database"); + req = mozContacts.clear() + req.onsuccess = function () { + ok(true, "Deleted the database"); + next(); + } + req.onerror = onFailure; + }, + function () { + ok(true, "Adding contact for category search"); + createResult1 = new mozContact({name: ["5"], givenName: ["5"]}); + req = navigator.mozContacts.save(createResult1); + req.onsuccess = function () { + ok(createResult1.id, "The contact now has an ID."); + sample_id1 = createResult1.id; + next(); + }; + req.onerror = onFailure; + }, + function () { + ok(true, "Test category search with equals"); + var options = {filterBy: ["givenName"], + filterOp: "startsWith", + filterValue: "5"}; + req = mozContacts.find(options); + req.onsuccess = function () { + is(req.result.length, 1, "1 Entry."); + checkContacts(req.result[0], createResult1); + next(); + } + req.onerror = onFailure; + }, + function () { + ok(true, "Deleting database"); + req = mozContacts.clear() + req.onsuccess = function () { + ok(true, "Deleted the database"); + next(); + } + req.onerror = onFailure; + }, + function () { + ok(true, "Adding contact with invalid data"); + var obj = { + honorificPrefix: [], + honorificSuffix: [{foo: "bar"}], + sex: 17, + genderIdentity: 18, + email: [{type: ["foo"], value: "bar"}] + }; + obj.honorificPrefix.__defineGetter__('0',(function() { + var c = 0; + return function() { + if (c == 0) { + c++; + return "string"; + } else { + return {foo:"bar"}; + } + } + })()); + createResult1 = new mozContact(obj); + createResult1.email.push({aeiou: "abcde"}); + req = mozContacts.save(createResult1); + req.onsuccess = function () { + checkContacts(createResult1, { + honorificPrefix: ["string"], + honorificSuffix: ["[object Object]"], + sex: "17", + genderIdentity: "18", + email: [{type: ["foo"], value: "bar"}, {}] + }); + next(); + }; + }, + function () { + ok(true, "Adding contact with no number but carrier"); + createResult1 = new mozContact({ tel: [{type: ["home"], carrier: "myCarrier"} ] }); + req = navigator.mozContacts.save(createResult1); + req.onsuccess = function () { + ok(createResult1.id, "The contact now has an ID."); + next(); + }; + req.onerror = onFailure; + }, + function () { + ok(true, "Adding contact with email but no value"); + createResult1 = new mozContact({ email: [{type: ["home"]}] }); + req = navigator.mozContacts.save(createResult1); + req.onsuccess = function () { + ok(createResult1.id, "The contact now has an ID."); + next(); + }; + req.onerror = onFailure; + }, + function () { + ok(true, "Testing numbersOnly search 1"); + createResult1 = new mozContact({ name: ["aaaaaaaaa"], givenName: ["aaaaaaaaa"], tel: [{ value: "1234567890"}]}); + req = navigator.mozContacts.save(createResult1); + req.onsuccess = function () { + ok(createResult1.id, "The contact now has an ID."); + next(); + }; + req.onerror = onFailure; + }, + function () { + ok(true, "Test numbersOnly search 2"); + var options = {filterBy: ["givenName", "tel"], + filterOp: "contains", + filterValue: "a"}; + req = mozContacts.find(options); + req.onsuccess = function () { + ok(req.result.length == 1, "1 Entry."); + checkContacts(req.result[0], createResult1); + next(); + } + req.onerror = onFailure; + }, + function () { + ok(true, "Test numbersOnly search 3"); + var options = {filterBy: ["givenName", "tel"], + filterOp: "contains", + filterValue: "b"}; + req = mozContacts.find(options); + req.onsuccess = function () { + ok(req.result.length == 0, "0 Entries."); + next(); + } + req.onerror = onFailure; + }, + function () { + ok(true, "Test numbersOnly search 4"); + var options = {filterBy: ["givenName", "tel"], + filterOp: "contains", + filterValue: "1a"}; + req = mozContacts.find(options); + req.onsuccess = function () { + ok(req.result.length == 0, "0 Entries."); + next(); + } + req.onerror = onFailure; + }, + function () { + ok(true, "Test numbersOnly search 5"); + var options = {filterBy: ["givenName", "tel"], + filterOp: "contains", + filterValue: "1(23)"}; + req = mozContacts.find(options); + req.onsuccess = function () { + ok(req.result.length == 1, "1 Entry."); + next(); + } + req.onerror = onFailure; + }, + function () { + ok(true, "Test numbersOnly search 6"); + var options = {filterBy: ["givenName", "tel"], + filterOp: "contains", + filterValue: "1(23)a"}; + req = mozContacts.find(options); + req.onsuccess = function () { + ok(req.result.length == 0, "0 Entries."); + next(); + } + req.onerror = onFailure; + }, + function () { + ok(true, "Deleting database"); + req = mozContacts.clear() + req.onsuccess = function () { + ok(true, "Deleted the database"); + next(); + } + req.onerror = onFailure; + }, + function() { + ok(true, "Test that after setting array properties to scalar values the property os not a non-array") + const FIELDS = ["email","url","adr","tel","impp"]; + createResult1 = new mozContact(); + for (var prop of FIELDS) { + try { + createResult1[prop] = {type: ["foo"]}; + } catch (e) {} + ok(createResult1[prop] === null || + Array.isArray(createResult1[prop]), prop + " is array"); + } + next(); + }, + function() { + ok(true, "Undefined properties of fields should be treated correctly"); + var c = new mozContact({ + adr: [{streetAddress: undefined}], + email: [{value: undefined}], + url: [{value: undefined}], + impp: [{value: undefined}], + tel: [{value: undefined}], + }); + is(c.adr[0].streetAddress, undefined, "adr.streetAddress is undefined"); + is(c.adr[0].locality, undefined, "adr.locality is undefined"); + is(c.adr[0].pref, undefined, "adr.pref is undefined"); + is(c.email[0].value, undefined, "email.value is undefined"); + is(c.url[0].value, undefined, "url.value is undefined"); + is(c.impp[0].value, undefined, "impp.value is undefined"); + is(c.tel[0].value, undefined, "tel.value is undefined"); + next(); + }, + function() { + ok(true, "Setting array properties to an empty array should work"); + var c = new mozContact(); + function testArrayProp(prop) { + is(c[prop], null, "property is initially null"); + c[prop] = []; + ok(Array.isArray(c[prop]), "property is an array after setting"); + is(c[prop].length, 0, "property has length 0 after setting"); + } + testArrayProp("email"); + testArrayProp("adr"); + testArrayProp("tel"); + testArrayProp("impp"); + testArrayProp("url"); + next(); + }, + function() { + ok(true, "Passing a mozContact with invalid data to save() should throw"); + var c = new mozContact({ + photo: [], + tel: [] + }); + c.photo.push({}); + SimpleTest.doesThrow(()=>navigator.mozContacts.save(c), "Invalid data in Blob array"); + c.tel.push(123); + SimpleTest.doesThrow(()=>navigator.mozContacts.save(c), "Invalid data in dictionary array"); + next(); + }, + function() { + ok(true, "Inline changes to array properties should be seen by save"); + var c = new mozContact({ + name: [], + familyName: [], + givenName: [], + phoneticFamilyName: [], + phoneticGivenName: [], + nickname: [], + tel: [], + adr: [], + email: [] + }); + for (var prop of Object.getOwnPropertyNames(properties1)) { + if (!Array.isArray(properties1[prop])) { + continue; + } + for (var i = 0; i < properties1[prop].length; ++i) { + c[prop].push(properties1[prop][i]); + } + } + req = navigator.mozContacts.save(c); + req.onsuccess = function() { + req = navigator.mozContacts.find(defaultOptions); + req.onsuccess = function() { + is(req.result.length, 1, "Got 1 contact"); + checkContacts(req.result[0], properties1); + next(); + }; + req.onerror = onFailure; + }; + req.onerror = onFailure; + }, + clearDatabase, + function() { + ok(true, "mozContact.init deprecation message"); + var c = new mozContact(); + SimpleTest.monitorConsole(next, [ + { errorMessage: "mozContact.init is DEPRECATED. Use the mozContact constructor instead. " + + "See https://developer.mozilla.org/docs/WebAPI/Contacts for details." } + ], /* forbidUnexpectedMsgs */ true); + c.init({name: ["Bar"]}); + c.init({name: ["Bar"]}); + SimpleTest.endMonitorConsole(); + }, + function() { + ok(true, "mozContact.init works as expected"); + var c = new mozContact({name: ["Foo"]}); + c.init({name: ["Bar"]}); + is(c.name[0], "Bar", "Same name"); + next(); + }, + function() { + ok(true, "mozContact.init without parameters"); + var c = new mozContact({name: ["Foo"]}); + c.init(); + next(); + }, + function() { + ok(true, "mozContact.init resets properties"); + var c = new mozContact({jobTitle: ["Software Engineer"]}); + c.init({nickname: ["Jobless Johnny"]}); + is(c.nickname[0], "Jobless Johnny", "Same nickname"); + ok(!c.jobTitle, "jobTitle is not set"); + next(); + }, + function() { + ok(true, "mozContacts.remove with an ID works"); + var c = new mozContact({name: ["Ephemeral Jimmy"]}); + req = navigator.mozContacts.save(c); + req.onsuccess = function() { + req = navigator.mozContacts.remove(c.id); + req.onsuccess = function() { + req = navigator.mozContacts.find({ + filterBy: ["id"], + filterOp: "equals", + filterValue: c.id + }); + req.onsuccess = function() { + is(req.result.length, 0, "Successfully removed contact by ID"); + next(); + }; + req.onerror = onFailure; + }; + req.onerror = onFailure; + }; + req.onerror = onFailure; + }, + function () { + ok(true, "Adding a new contact"); + createResult1 = new mozContact(properties3); + req = mozContacts.save(createResult1) + req.onsuccess = function () { + ok(createResult1.id, "The contact now has an ID."); + sample_id1 = createResult1.id; + next(); + } + req.onerror = onFailure; + }, + function () { + ok(true, "Adding a new contact2"); + createResult2 = new mozContact(properties4); + req = mozContacts.save(createResult2); + req.onsuccess = function () { + ok(createResult2.id, "The contact now has an ID."); + sample_id2 = createResult2.id; + next(); + }; + req.onerror = onFailure; + }, + function () { + ok(true, "Retrieving all contacts"); + req = mozContacts.find({sortBy: "phoneticFamilyName"}); + req.onsuccess = function () { + is(req.result.length, 2, "Found exactly 2 contact."); + checkContacts(req.result[1], properties3); + next(); + } + req.onerror = onFailure; + }, + function () { + ok(true, "Searching contacts by query1"); + var options = {filterBy: ["phoneticGivenName", "email"], + filterOp: "startsWith", + filterValue: properties3.phoneticGivenName[0].substring(0, 3)} + req = mozContacts.find(options) + req.onsuccess = function () { + is(req.result.length, 1, "Found exactly 1 contact."); + findResult1 = req.result[0]; + ok(findResult1.id == sample_id1, "Same ID"); + checkContacts(findResult1, createResult1); + next(); + } + req.onerror = onFailure; + }, + function () { + ok(true, "Searching contacts by query2"); + var options = {filterBy: ["phoneticGivenName", "email"], + filterOp: "startsWith", + filterValue: properties4.phoneticGivenName[0].substring(0, 3)}; + req = mozContacts.find(options); + req.onsuccess = function () { + is(req.result.length, 1, "Found exactly 1 contact."); + findResult1 = req.result[0]; + is(findResult1.adr.length, 2, "Adr length 2"); + checkContacts(findResult1, createResult2); + next(); + } + req.onerror = onFailure; + }, + clearDatabase, + function () { + ok(true, "Adding 20 contacts"); + for (var i=0; i<19; i++) { + createResult1 = new mozContact(properties3); + req = mozContacts.save(createResult1); + req.onsuccess = function () { + ok(createResult1.id, "The contact now has an ID."); + }; + req.onerror = onFailure; + }; + createResult1 = new mozContact(properties3); + req = mozContacts.save(createResult1); + req.onsuccess = function () { + ok(createResult1.id, "The contact now has an ID."); + checkStrArray(createResult1.name, properties3.name, "Same Name"); + checkCount(20, "20 contacts in DB", next); + }; + req.onerror = onFailure; + }, + function () { + ok(true, "Retrieving all contacts"); + req = mozContacts.find(defaultOptions); + req.onsuccess = function () { + is(req.result.length, 20, "20 Entries."); + next(); + } + req.onerror = onFailure; + }, + function () { + ok(true, "Retrieving all contacts2"); + var options = {filterBy: ["phoneticGivenName"], + filterOp: "startsWith", + filterValue: properties3.phoneticGivenName[0].substring(0, 3)}; + req = mozContacts.find(options); + req.onsuccess = function () { + is(req.result.length, 20, "20 Entries."); + checkContacts(createResult1, req.result[19]); + next(); + } + req.onerror = onFailure; + }, + function () { + ok(true, "Retrieving all contacts3"); + var options = {filterBy: ["phoneticGivenName", "tel", "email"], + filterOp: "startsWith", + filterValue: properties3.phoneticGivenName[0].substring(0, 3)}; + req = mozContacts.find(options); + req.onsuccess = function () { + is(req.result.length, 20, "20 Entries."); + checkContacts(createResult1, req.result[10]); + next(); + } + req.onerror = onFailure; + }, + clearDatabase, + function () { + ok(true, "Testing clone contact"); + createResult1 = new mozContact(properties3); + req = mozContacts.save(createResult1); + req.onsuccess = function () { + ok(createResult1.id, "The contact now has an ID."); + checkStrArray(createResult1.phoneticFamilyName, properties3.phoneticFamilyName, "Same phoneticFamilyName"); + checkStrArray(createResult1.phoneticGivenName, properties3.phoneticGivenName, "Same phoneticGivenName"); + next(); + } + req.onerror = onFailure; + }, + function () { + ok(true, "Retrieving all contacts"); + req = mozContacts.find({sortBy: "phoneticGivenName"}); + req.onsuccess = function () { + is(req.result.length, 1, "1 Entries."); + next(); + } + req.onerror = onFailure; + }, + clearDatabase, + function () { + ok(true, "Test sorting"); + createResult1 = new mozContact(c11); + req = navigator.mozContacts.save(createResult1); + req.onsuccess = function () { + ok(createResult1.id, "The contact now has an ID."); + checkContacts(c11, createResult1); + next(); + }; + req.onerror = onFailure; + }, + function () { + ok(true, "Test sorting"); + createResult1 = new mozContact(c10); + req = navigator.mozContacts.save(createResult1); + req.onsuccess = function () { + ok(createResult1.id, "The contact now has an ID."); + checkContacts(c10, createResult1); + next(); + }; + req.onerror = onFailure; + }, + function () { + ok(true, "Test sorting"); + createResult1 = new mozContact(c12); + req = navigator.mozContacts.save(createResult1); + req.onsuccess = function () { + ok(createResult1.id, "The contact now has an ID."); + checkContacts(c12, createResult1); + next(); + }; + req.onerror = onFailure; + }, + function () { + ok(true, "Test sorting"); + createResult1 = new mozContact(c9); + req = navigator.mozContacts.save(createResult1); + req.onsuccess = function () { + ok(createResult1.id, "The contact now has an ID."); + checkContacts(c9, createResult1); + next(); + }; + req.onerror = onFailure; + }, + function () { + ok(true, "Test sorting"); + var options = {sortBy: "phoneticFamilyName", + sortOrder: "ascending"}; + req = navigator.mozContacts.find(options); + req.onsuccess = function () { + is(req.result.length, 4, "4 results"); + checkContacts(req.result[0], c9); + checkContacts(req.result[1], c10); + checkContacts(req.result[2], c11); + checkContacts(req.result[3], c12); + next(); + }; + req.onerror = onFailure; + }, + function () { + ok(true, "Test sorting"); + var options = {sortBy: "phoneticFamilyName", + sortOrder: "descending"}; + req = navigator.mozContacts.find(options); + req.onsuccess = function () { + is(req.result.length, 4, "4 results"); + checkContacts(req.result[0], c12); + checkContacts(req.result[1], c11); + checkContacts(req.result[2], c10); + checkContacts(req.result[3], c9); + next(); + }; + req.onerror = onFailure; + }, + function () { + ok(true, "Test sorting"); + createResult1 = new mozContact(c13); + req = navigator.mozContacts.save(createResult1); + req.onsuccess = function () { + ok(createResult1.id, "The contact now has an ID."); + checkContacts(c13, createResult1); + next(); + }; + req.onerror = onFailure; + }, + function () { + ok(true, "Test sorting with empty string"); + var options = {sortBy: "phoneticFamilyName", + sortOrder: "ascending"}; + req = navigator.mozContacts.find(options); + req.onsuccess = function () { + is(req.result.length, 5, "5 results"); + checkContacts(req.result[0], c13); + checkContacts(req.result[1], c9); + checkContacts(req.result[2], c10); + checkContacts(req.result[3], c11); + checkContacts(req.result[4], c12); + next(); + }; + req.onerror = onFailure; + }, + clearDatabase, + function () { + ok(true, "Test sorting"); + createResult1 = new mozContact(c15); + req = navigator.mozContacts.save(createResult1); + req.onsuccess = function () { + ok(createResult1.id, "The contact now has an ID."); + checkContacts(c15, createResult1); + next(); + }; + req.onerror = onFailure; + }, + function () { + ok(true, "Test sorting"); + createResult1 = new mozContact(c14); + req = navigator.mozContacts.save(createResult1); + req.onsuccess = function () { + ok(createResult1.id, "The contact now has an ID."); + checkContacts(c14, createResult1); + next(); + }; + req.onerror = onFailure; + }, + function () { + ok(true, "Test sorting"); + createResult1 = new mozContact(c16); + req = navigator.mozContacts.save(createResult1); + req.onsuccess = function () { + ok(createResult1.id, "The contact now has an ID."); + checkContacts(c16, createResult1); + next(); + }; + req.onerror = onFailure; + }, + function () { + // Android does not support published/updated fields. Skip this. + if (isAndroid) { + next(); + return; + } + + ok(true, "Test sorting with published"); + var options = {sortBy: "phoneticFamilyName", + sortOrder: "descending"}; + req = navigator.mozContacts.find(options); + req.onsuccess = function () { + is(req.result.length, 3, "3 results"); + ok(req.result[0].published < req.result[1].published, "Right sorting order"); + ok(req.result[1].published < req.result[2].published, "Right sorting order"); + next(); + }; + req.onerror = onFailure; + }, + clearDatabase, + function () { + ok(true, "all done!\n"); + parent.SimpleTest.finish(); + } +]; + +function next() { + ok(true, "Begin!"); + if (index >= steps.length) { + ok(false, "Shouldn't get here!"); + return; + } + try { + var i = index++; + steps[i](); + } catch(ex) { + ok(false, "Caught exception", ex); + } +} + +start_tests(); +</script> +</pre> +</body> +</html>
new file mode 100644 --- /dev/null +++ b/dom/contacts/tests/file_contacts_blobs.html @@ -0,0 +1,226 @@ +<!DOCTYPE html> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=674720 +--> +<head> + <title>Test for Bug 674720 WebContacts</title> + <script type="text/javascript" src="/MochiKit/MochiKit.js"></script> + <script type="text/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=674720">Mozilla Bug 674720</a> +<p id="display"></p> +<div id="content" style="display: none"> + +</div> +<pre id="test"> +<script type="text/javascript;version=1.8" src="http://mochi.test:8888/tests/dom/contacts/tests/shared.js"></script> +<script class="testbody" type="text/javascript"> +"use strict"; + +var ok = parent.ok; +var is = parent.is; +var isnot = parent.isnot; + +var utils = SpecialPowers.getDOMWindowUtils(window); + +function getView(size) +{ + var buffer = new ArrayBuffer(size); + var view = new Uint8Array(buffer); + is(buffer.byteLength, size, "Correct byte length"); + return view; +} + +function getRandomView(size) +{ + var view = getView(size); + for (var i = 0; i < size; i++) { + view[i] = parseInt(Math.random() * 255) + } + return view; +} + +function getRandomBlob(size) +{ + return new Blob([getRandomView(size)], { type: "binary/random" }); +} + +function compareBuffers(buffer1, buffer2) +{ + if (buffer1.byteLength != buffer2.byteLength) { + return false; + } + var view1 = new Uint8Array(buffer1); + var view2 = new Uint8Array(buffer2); + for (var i = 0; i < buffer1.byteLength; i++) { + if (view1[i] != view2[i]) { + return false; + } + } + return true; +} + +function verifyBuffers(buffer1, buffer2, isLast) +{ + ok(compareBuffers(buffer1, buffer2), "Correct blob data"); + if (isLast) + next(); +} + +var randomBlob = getRandomBlob(1024); +var randomBlob2 = getRandomBlob(1024); + +var properties1 = { + name: ["xTestname1"], + givenName: ["xTestname1"], + photo: [randomBlob] +}; + +var properties2 = { + name: ["yTestname2"], + givenName: ["yTestname2"], + photo: [randomBlob, randomBlob2] +}; + +var sample_id1; +var createResult1; +var findResult1; + +function verifyBlob(blob1, blob2, isLast) +{ + is(blob1 instanceof Blob, true, + "blob1 is an instance of DOMBlob"); + is(blob2 instanceof Blob, true, + "blob2 is an instance of DOMBlob"); + isnot(blob1 instanceof File, true, + "blob1 is an instance of File"); + isnot(blob2 instanceof File, true, + "blob2 is an instance of File"); + is(blob1.size, blob2.size, "Same size"); + is(blob1.type, blob2.type, "Same type"); + + var buffer1; + var buffer2; + + var reader1 = new FileReader(); + reader1.readAsArrayBuffer(blob2); + reader1.onload = function(event) { + buffer2 = event.target.result; + if (buffer1) { + verifyBuffers(buffer1, buffer2, isLast); + } + } + + var reader2 = new FileReader(); + reader2.readAsArrayBuffer(blob1); + reader2.onload = function(event) { + buffer1 = event.target.result; + if (buffer2) { + verifyBuffers(buffer1, buffer2, isLast); + } + } +} + +function verifyBlobArray(blobs1, blobs2) +{ + is(blobs1 instanceof Array, true, "blobs1 is an array object"); + is(blobs2 instanceof Array, true, "blobs2 is an array object"); + is(blobs1.length, blobs2.length, "Same length"); + + if (!blobs1.length) { + next(); + return; + } + + for (var i = 0; i < blobs1.length; i++) { + verifyBlob(blobs1[i], blobs2[i], i == blobs1.length - 1); + } +} + +var req; + +var steps = [ + function () { + ok(true, "Deleting database"); + req = mozContacts.clear(); + req.onsuccess = function () { + ok(true, "Deleted the database"); + next(); + }; + req.onerror = onFailure; + }, + function () { + ok(true, "Adding contact with photo"); + createResult1 = new mozContact(properties1); + req = navigator.mozContacts.save(createResult1); + req.onsuccess = function () { + ok(createResult1.id, "The contact now has an ID."); + sample_id1 = createResult1.id; + next(); + }; + req.onerror = onFailure; + }, + function () { + ok(true, "Retrieving by substring"); + var options = {filterBy: ["givenName"], + filterOp: "startsWith", + filterValue: properties1.givenName[0].substring(0,3)}; + req = mozContacts.find(options); + req.onsuccess = function () { + ok(req.result.length == 1, "Found exactly 1 contact."); + findResult1 = req.result[0]; + ok(findResult1.id == sample_id1, "Same ID"); + verifyBlobArray(findResult1.photo, properties1.photo); + }; + req.onerror = onFailure; + }, + function () { + ok(true, "Adding contact with 2 photos"); + createResult1 = new mozContact(properties2); + req = navigator.mozContacts.save(createResult1); + req.onsuccess = function () { + ok(createResult1.id, "The contact now has an ID."); + sample_id1 = createResult1.id; + next(); + }; + req.onerror = onFailure; + }, + function () { + ok(true, "Retrieving by substring"); + var options = {filterBy: ["givenName"], + filterOp: "startsWith", + filterValue: properties2.givenName[0].substring(0,3)}; + req = mozContacts.find(options); + req.onsuccess = function () { + ok(req.result.length == 1, "Found exactly 1 contact."); + findResult1 = req.result[0]; + ok(findResult1.id == sample_id1, "Same ID"); + verifyBlobArray(findResult1.photo, properties2.photo); + }; + req.onerror = onFailure; + }, + function () { + ok(true, "Deleting database"); + req = mozContacts.clear() + req.onsuccess = function () { + ok(true, "Deleted the database"); + next(); + } + req.onerror = onFailure; + }, + function () { + ok(true, "all done!\n"); + + parent.SimpleTest.finish(); + } +]; + +start_tests(); +</script> +</pre> +</body> +</html>
new file mode 100644 --- /dev/null +++ b/dom/contacts/tests/file_contacts_events.html @@ -0,0 +1,43 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=764667 +--> +<head> + <title>Test for Bug 678695</title> + <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=764667">Mozilla Bug 764667</a> +<p id="display"></p> +<div id="content" style="display: none"> + +</div> +<pre id="test"> +<script type="application/javascript"> + +/** Test for Bug 764667 **/ + +var ok = parent.ok; +var is = parent.is; + +var e = new MozContactChangeEvent("contactchanged", {contactID: "123", reason: "create"}); +ok(e, "Should have contactsChange event!"); +is(e.contactID, "123", "ID should be 123."); +is(e.reason, "create", "Reason should be create."); + +e = new MozContactChangeEvent("contactchanged", {contactID: "test", reason: "test"}); +is(e.contactID, "test", "Name should be 'test'."); +is(e.reason, "test", "Name should be 'test'."); + +e = new MozContactChangeEvent("contactchanged", {contactID: "a", reason: ""}); +is(e.contactID, "a", "Name should be a."); +is(e.reason, "", "Value should be empty"); + +parent.SimpleTest.finish(); + +</script> +</pre> +</body> +</html>
new file mode 100644 --- /dev/null +++ b/dom/contacts/tests/file_contacts_getall.html @@ -0,0 +1,156 @@ +<!DOCTYPE html> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=836519 +--> +<head> + <title>Mozilla Bug 836519</title> + <script type="text/javascript" src="/MochiKit/MochiKit.js"></script> + <script type="text/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=836519">Mozilla Bug 836519</a> +<p id="display"></p> +<div id="content" style="display: none"> + +</div> +<pre id="test"> +<script type="text/javascript;version=1.8" src="http://mochi.test:8888/tests/dom/contacts/tests/shared.js"></script> +<script class="testbody" type="text/javascript;version=1.8"> +"use strict"; + +var ok = parent.ok; +var is = parent.is; +var isnot = parent.isnot; + +let req; + +let steps = [ + function start() { + SpecialPowers.Cc["@mozilla.org/tools/profiler;1"].getService(SpecialPowers.Ci.nsIProfiler).AddMarker("GETALL_START"); + next(); + }, + clearDatabase, + addContacts, + + function() { + ok(true, "Delete the current contact while iterating"); + req = mozContacts.getAll({}); + let count = 0; + let previousId = null; + req.onsuccess = function() { + if (req.result) { + ok(true, "on success"); + if (previousId) { + isnot(previousId, req.result.id, "different contacts returned"); + } + previousId = req.result.id; + count++; + let delReq = mozContacts.remove(req.result); + delReq.onsuccess = function() { + ok(true, "deleted current contact"); + req.continue(); + }; + } else { + is(count, 40, "returned 40 contacts"); + next(); + } + }; + }, + + clearDatabase, + addContacts, + + function() { + ok(true, "Iterating through the contact list inside a cursor callback"); + let count1 = 0, count2 = 0; + let req1 = mozContacts.getAll({}); + let req2; + req1.onsuccess = function() { + if (count1 == 0) { + count1++; + req2 = mozContacts.getAll({}); + req2.onsuccess = function() { + if (req2.result) { + count2++; + req2.continue(); + } else { + is(count2, 40, "inner cursor returned 40 contacts"); + req1.continue(); + } + }; + } else { + if (req1.result) { + count1++; + req1.continue(); + } else { + is(count1, 40, "outer cursor returned 40 contacts"); + next(); + } + } + }; + }, + + clearDatabase, + addContacts, + + function() { + ok(true, "20 concurrent cursors"); + const NUM_CURSORS = 20; + let completed = 0; + for (let i = 0; i < NUM_CURSORS; ++i) { + mozContacts.getAll({}).onsuccess = (function(i) { + let count = 0; + return function(event) { + let req = event.target; + if (req.result) { + count++; + req.continue(); + } else { + is(count, 40, "cursor " + i + " returned 40 contacts"); + if (++completed == NUM_CURSORS) { + next(); + } + } + }; + })(i); + } + }, + + clearDatabase, + addContacts, + + function() { + if (!SpecialPowers.isMainProcess()) { + // We stop calling continue() intentionally here to see if the cursor gets + // cleaned up properly in the parent. + ok(true, "Leaking a cursor"); + req = mozContacts.getAll({ + sortBy: "familyName", + sortOrder: "ascending" + }); + req.onsuccess = function(event) { + next(); + }; + req.onerror = onFailure; + } else { + next(); + } + }, + + clearDatabase, + + function() { + ok(true, "all done!\n"); + SpecialPowers.Cc["@mozilla.org/tools/profiler;1"].getService(SpecialPowers.Ci.nsIProfiler).AddMarker("GETALL_END"); + parent.SimpleTest.finish(); + } +]; + +start_tests(); +</script> +</pre> +</body> +</html>
new file mode 100644 --- /dev/null +++ b/dom/contacts/tests/file_contacts_getall2.html @@ -0,0 +1,124 @@ +<!DOCTYPE html> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=836519 +--> +<head> + <title>Mozilla Bug 836519</title> + <script type="text/javascript" src="/MochiKit/MochiKit.js"></script> + <script type="text/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=836519">Mozilla Bug 836519</a> +<p id="display"></p> +<div id="content" style="display: none"> + +</div> +<pre id="test"> +<script type="text/javascript;version=1.8" src="http://mochi.test:8888/tests/dom/contacts/tests/shared.js"></script> +<script class="testbody" type="text/javascript;version=1.8"> +"use strict"; + +var ok = parent.ok; +var is = parent.is; + +let req; + +let steps = [ + clearDatabase, + function() { + // add a contact + createResult1 = new mozContact({}); + req = navigator.mozContacts.save(createResult1); + req.onsuccess = function() { + next(); + }; + req.onerror = onFailure; + }, + + getOne(), + getOne("Retrieving one contact with getAll - cached"), + + clearDatabase, + addContacts, + + getAll(), + getAll("Retrieving 40 contacts with getAll - cached"), + + function() { + ok(true, "Deleting one contact"); + req = mozContacts.remove(createResult1); + req.onsuccess = function() { + next(); + }; + req.onerror = onFailure; + }, + function() { + ok(true, "Test cache invalidation"); + req = mozContacts.getAll({}); + let count = 0; + req.onsuccess = function(event) { + ok(true, "on success"); + if (req.result) { + ok(true, "result is valid"); + count++; + req.continue(); + } else { + is(count, 39, "last contact - 39 contacts returned"); + next(); + } + }; + req.onerror = onFailure; + }, + + clearDatabase, + addContacts, + + function() { + ok(true, "Test cache consistency when deleting contact during getAll"); + req = mozContacts.find({}); + req.onsuccess = function(e) { + let lastContact = e.target.result[e.target.result.length-1]; + req = mozContacts.getAll({}); + let count = 0; + let firstResult = true; + req.onsuccess = function(event) { + ok(true, "on success"); + if (firstResult) { + if (req.result) { + count++; + } + let delReq = mozContacts.remove(lastContact); + delReq.onsuccess = function() { + firstResult = false; + req.continue(); + }; + } else { + if (req.result) { + ok(true, "result is valid"); + count++; + req.continue(); + } else { + is(count, 40, "last contact - 40 contacts returned"); + next(); + } + } + }; + }; + }, + + clearDatabase, + + function() { + ok(true, "all done!\n"); + parent.SimpleTest.finish(); + } +]; + +start_tests(); +</script> +</pre> +</body> +</html>
new file mode 100644 --- /dev/null +++ b/dom/contacts/tests/file_contacts_international.html @@ -0,0 +1,277 @@ +<!DOCTYPE html> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=815833 +--> +<head> + <title>Test for Bug 815833 WebContacts</title> + <script type="text/javascript" src="/MochiKit/MochiKit.js"></script> + <script type="text/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=815833">Mozilla Bug 815833</a> +<p id="display"></p> +<div id="content" style="display: none"> + +</div> +<pre id="test"> +<script type="text/javascript;version=1.8" src="http://mochi.test:8888/tests/dom/contacts/tests/shared.js"></script> +<script class="testbody" type="text/javascript"> +"use strict"; + +var ok = parent.ok; +var ise = parent.ise; + +var number1 = { + local: "7932012345", + international: "+557932012345" +}; + +var number2 = { + local: "7932012346", + international: "+557932012346" +}; + +var properties1 = { + name: ["Testname1"], + tel: [{type: ["work"], value: number1.local, carrier: "testCarrier"} , {type: ["home", "fax"], value: number2.local}], +}; + +var shortNumber = "888"; +var properties2 = { + name: ["Testname2"], + tel: [{type: ["work"], value: shortNumber, carrier: "testCarrier"}] +}; + +var number3 = { + local: "7932012345", + international: "+557932012345" +}; + +var properties3 = { + name: ["Testname2"], + tel: [{value: number3.international}] +}; + +var req; +var createResult1; +var findResult1; +var sample_id1; + +var steps = [ + function () { + ok(true, "Deleting database"); + req = mozContacts.clear(); + req.onsuccess = function () { + ok(true, "Deleted the database"); + next(); + }; + req.onerror = onFailure; + }, + function () { + ok(true, "Adding a new contact1"); + createResult1 = new mozContact(properties1); + req = navigator.mozContacts.save(createResult1); + req.onsuccess = function () { + ok(createResult1.id, "The contact now has an ID."); + sample_id1 = createResult1.id; + next(); + }; + req.onerror = onFailure; + }, + function () { + ok(true, "Adding a new contact2"); + var createResult2 = new mozContact(properties2); + req = navigator.mozContacts.save(createResult2); + req.onsuccess = function () { + ok(createResult2.id, "The contact now has an ID."); + next(); + }; + req.onerror = onFailure; + }, + function () { + ok(true, "Searching for local number"); + var options = {filterBy: ["tel"], + filterOp: "startsWith", + filterValue: number1.local}; + req = mozContacts.find(options); + req.onsuccess = function () { + is(req.result.length, 1, "Found exactly 1 contact."); + findResult1 = req.result[0]; + is(findResult1.id, sample_id1, "Same ID"); + next(); + }; + req.onerror = onFailure; + }, + function () { + ok(true, "Searching for international number"); + var options = {filterBy: ["tel"], + filterOp: "startsWith", + filterValue: number1.international}; + req = mozContacts.find(options); + req.onsuccess = function () { + is(req.result.length, 0, "Found exactly 0 contacts."); + next(); + }; + req.onerror = onFailure; + }, + function () { + ok(true, "Searching for a short number matching the prefix"); + var shortNumber = number1.local.substring(0, 3); + var options = {filterBy: ["tel"], + filterOp: "equals", + filterValue: shortNumber}; + req = mozContacts.find(options); + req.onsuccess = function() { + is(req.result.length, 0, "The prefix short number should not match any contact."); + next(); + }; + req.onerror = onFailure; + }, + function () { + ok(true, "Searching for a short number matching the suffix"); + var shortNumber = number1.local.substring(number1.local.length - 3); + var options = {filterBy: ["tel"], + filterOp: "equals", + filterValue: shortNumber}; + req = mozContacts.find(options); + req.onsuccess = function() { + is(req.result.length, 0, "The suffix short number should not match any contact."); + next(); + }; + req.onerror = onFailure; + }, + function () { + ok(true, "Searching for a short number matching a contact"); + var options = {filterBy: ["tel"], + filterOp: "equals", + filterValue: shortNumber}; + req = mozContacts.find(options); + req.onsuccess = function() { + is(req.result.length, 1, "Found the contact equally matching the shortNumber."); + next(); + }; + req.onerror = onFailure; + }, + function() { + ok(true, "Modifying number"); + if (!findResult1) { + SpecialPowers.executeSoon(next); + } else { + findResult1.tel[0].value = number2.local; + req = mozContacts.save(findResult1); + req.onsuccess = function () { + next(); + }; + } + }, + function () { + ok(true, "Searching for local number"); + var options = {filterBy: ["tel"], + filterOp: "startsWith", + filterValue: number1.local}; + req = mozContacts.find(options); + req.onsuccess = function () { + is(req.result.length, 0, "Found exactly 0 contact."); + next(); + }; + req.onerror = onFailure; + }, + function () { + ok(true, "Searching for local number"); + var options = {filterBy: ["tel"], + filterOp: "startsWith", + filterValue: number1.international}; + req = mozContacts.find(options); + req.onsuccess = function () { + is(req.result.length, 0, "Found exactly 0 contact."); + next(); + }; + req.onerror = onFailure; + }, + function () { + ok(true, "Searching for local number"); + var options = {filterBy: ["tel"], + filterOp: "startsWith", + filterValue: number2.local}; + req = mozContacts.find(options); + req.onsuccess = function () { + is(req.result.length, 1, "Found exactly 1 contact."); + findResult1 = req.result[0]; + is(findResult1.id, sample_id1, "Same ID"); + next(); + }; + req.onerror = onFailure; + }, + function () { + ok(true, "Searching for local number"); + var options = {filterBy: ["tel"], + filterOp: "startsWith", + filterValue: number2.international}; + req = mozContacts.find(options); + req.onsuccess = function () { + is(req.result.length, 0, "Found exactly 1 contact."); + next(); + }; + req.onerror = onFailure; + }, + function () { + ok(true, "Deleting database"); + req = mozContacts.clear(); + req.onsuccess = function () { + ok(true, "Deleted the database"); + next(); + } + req.onerror = onFailure; + }, + function () { + ok(true, "Adding a contact with a Brazilian country code"); + createResult1 = new mozContact(properties3); + req = navigator.mozContacts.save(createResult1); + req.onsuccess = function () { + ok(createResult1.id, "The contact now has an ID."); + sample_id1 = createResult1.id; + next(); + }; + req.onerror = onFailure; + }, + function () { + ok(true, "Searching for Brazilian number using local number"); + var options = {filterBy: ["tel"], + filterOp: "match", + filterValue: number3.local}; + req = mozContacts.find(options); + req.onsuccess = function () { + is(req.result.length, 1, "Found exactly 1 contact."); + findResult1 = req.result[0]; + is(findResult1.id, sample_id1, "Same ID"); + next(); + }; + req.onerror = onFailure; + }, + function () { + ok(true, "Deleting database"); + req = mozContacts.clear(); + req.onsuccess = function () { + ok(true, "Deleted the database"); + next(); + } + req.onerror = onFailure; + }, + function () { + ok(true, "all done!\n"); + parent.SimpleTest.finish(); + } +]; + +SpecialPowers.pushPrefEnv({ + set: [ + ["ril.lastKnownSimMcc", "000"] + ] +}, start_tests); +</script> +</pre> +</body> +</html>
new file mode 100644 --- /dev/null +++ b/dom/contacts/tests/file_contacts_substringmatching.html @@ -0,0 +1,351 @@ +<!DOCTYPE html> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=877302 +--> +<head> + <title>Test for Bug 877302 substring matching for WebContacts</title> + <script type="text/javascript" src="/MochiKit/MochiKit.js"></script> + <script type="text/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=877302">Mozilla Bug 877302</a> +<p id="display"></p> +<div id="content" style="display: none"> + +</div> +<pre id="test"> +<script type="text/javascript;version=1.8" src="http://mochi.test:8888/tests/dom/contacts/tests/shared.js"></script> +<script class="testbody" type="text/javascript"> +"use strict"; + +var ok = parent.ok; +var is = parent.is; + +var substringLength = 8; + +var prop = { + tel: [{value: "7932012345" }, {value: "7932012346"}] +}; + +var prop2 = { + tel: [{value: "01187654321" }] +}; + +var prop3 = { + tel: [{ value: "+43332112346" }] +}; + +var prop4 = { + tel: [{ value: "(0414) 233-9888" }] +}; + +var brazilianNumber = { + international1: "0041557932012345", + international2: "+557932012345" +}; + +var prop5 = { + tel: [{value: brazilianNumber.international2}] +}; + +var req; +var steps = [ + function () { + ok(true, "Deleting database"); + req = mozContacts.clear() + req.onsuccess = function () { + ok(true, "Deleted the database"); + next(); + } + req.onerror = onFailure; + }, + function () { + ok(true, "Adding contact"); + createResult1 = new mozContact(prop); + req = navigator.mozContacts.save(createResult1); + req.onsuccess = function () { + ok(createResult1.id, "The contact now has an ID."); + sample_id1 = createResult1.id; + next(); + }; + req.onerror = onFailure; + }, + function () { + ok(true, "Retrieving all contacts"); + req = mozContacts.find({}); + req.onsuccess = function () { + is(req.result.length, 1, "One contact."); + findResult1 = req.result[0]; + next(); + }; + req.onerror = onFailure; + }, + function () { + ok(true, "Retrieving by substring 1"); + var length = prop.tel[0].value.length; + var num = prop.tel[0].value.substring(length - substringLength, length); + var options = {filterBy: ["tel"], + filterOp: "match", + filterValue: num}; + req = mozContacts.find(options); + req.onsuccess = function () { + is(req.result.length, 1, "Found exactly 1 contact."); + findResult1 = req.result[0]; + ok(findResult1.id == sample_id1, "Same ID"); + is(findResult1.tel[0].value, "7932012345", "Same Value"); + next(); + }; + req.onerror = onFailure; + }, + function () { + ok(true, "Retrieving by substring 2"); + var length = prop.tel[1].value.length; + var num = prop.tel[1].value.substring(length - substringLength, length); + var options = {filterBy: ["tel"], + filterOp: "match", + filterValue: num}; + req = mozContacts.find(options); + req.onsuccess = function () { + is(req.result.length, 1, "Found exactly 1 contact."); + findResult1 = req.result[0]; + ok(findResult1.id == sample_id1, "Same ID"); + is(findResult1.tel[0].value, "7932012345", "Same Value"); + next(); + }; + req.onerror = onFailure; + }, + function () { + ok(true, "Retrieving by substring 3"); + var length = prop.tel[0].value.length; + var num = prop.tel[0].value.substring(length - substringLength + 1, length); + var options = {filterBy: ["tel"], + filterOp: "match", + filterValue: num}; + req = mozContacts.find(options); + req.onsuccess = function () { + is(req.result.length, 0, "Found exactly 0 contacts."); + next(); + }; + req.onerror = onFailure; + }, + function () { + ok(true, "Retrieving by substring 4"); + var length = prop.tel[0].value.length; + var num = prop.tel[0].value.substring(length - substringLength - 1, length); + var options = {filterBy: ["tel"], + filterOp: "match", + filterValue: num}; + req = mozContacts.find(options); + req.onsuccess = function () { + is(req.result.length, 1, "Found exactly 1 contacts."); + next(); + }; + req.onerror = onFailure; + }, + function () { + ok(true, "Adding contact"); + createResult1 = new mozContact(prop2); + req = navigator.mozContacts.save(createResult1); + req.onsuccess = function () { + ok(createResult1.id, "The contact now has an ID."); + sample_id1 = createResult1.id; + next(); + }; + req.onerror = onFailure; + }, + function () { + ok(true, "Retrieving by substring 5"); + var options = {filterBy: ["tel"], + filterOp: "match", + filterValue: "87654321"}; + req = mozContacts.find(options); + req.onsuccess = function () { + is(req.result.length, 1, "Found exactly 1 contacts."); + next(); + }; + req.onerror = onFailure; + }, + function () { + ok(true, "Retrieving by substring 6"); + var options = {filterBy: ["tel"], + filterOp: "match", + filterValue: "01187654321"}; + req = mozContacts.find(options); + req.onsuccess = function () { + is(req.result.length, 1, "Found exactly 1 contacts."); + next(); + }; + req.onerror = onFailure; + }, + function () { + ok(true, "Retrieving by substring 7"); + var options = {filterBy: ["tel"], + filterOp: "match", + filterValue: "909087654321"}; + req = mozContacts.find(options); + req.onsuccess = function () { + is(req.result.length, 1, "Found exactly 1 contacts."); + next(); + }; + req.onerror = onFailure; + }, + function () { + ok(true, "Retrieving by substring 8"); + var options = {filterBy: ["tel"], + filterOp: "match", + filterValue: "0411187654321"}; + req = mozContacts.find(options); + req.onsuccess = function () { + is(req.result.length, 1, "Found exactly 1 contacts."); + next(); + }; + req.onerror = onFailure; + }, + function () { + ok(true, "Retrieving by substring 9"); + var options = {filterBy: ["tel"], + filterOp: "match", + filterValue: "90411187654321"}; + req = mozContacts.find(options); + req.onsuccess = function () { + is(req.result.length, 1, "Found exactly 1 contacts."); + next(); + }; + req.onerror = onFailure; + }, + function () { + ok(true, "Retrieving by substring 10"); + var options = {filterBy: ["tel"], + filterOp: "match", + filterValue: "+551187654321"}; + req = mozContacts.find(options); + req.onsuccess = function () { + is(req.result.length, 1, "Found exactly 1 contacts."); + next(); + }; + req.onerror = onFailure; + }, + function () { + ok(true, "Deleting database"); + req = mozContacts.clear() + req.onsuccess = function () { + ok(true, "Deleted the database"); + next(); + } + req.onerror = onFailure; + }, + function () { + ok(true, "Adding contact"); + createResult1 = new mozContact(prop3); + req = navigator.mozContacts.save(createResult1); + req.onsuccess = function () { + ok(createResult1.id, "The contact now has an ID."); + sample_id1 = createResult1.id; + next(); + }; + req.onerror = onFailure; + }, + function () { + if (!isAndroid) { // Bug 905927 + ok(true, "Retrieving by substring 1"); + var length = prop3.tel[0].value.length; + var num = prop3.tel[0].value.substring(length - substringLength, length); + var options = {filterBy: ["tel"], + filterOp: "match", + filterValue: num}; + req = mozContacts.find(options); + req.onsuccess = function () { + is(req.result.length, 0, "Found exactly 0 contacts."); + next(); + }; + req.onerror = onFailure; + } else { + SpecialPowers.executeSoon(next); + } + }, + function () { + ok(true, "Adding contact"); + createResult1 = new mozContact(prop4); + req = navigator.mozContacts.save(createResult1); + req.onsuccess = function () { + ok(createResult1.id, "The contact now has an ID."); + sample_id1 = createResult1.id; + next(); + }; + req.onerror = onFailure; + }, + function () { + ok(true, "Retrieving by substring 1"); + var num = "(0424) 233-9888" + var options = {filterBy: ["tel"], + filterOp: "match", + filterValue: num}; + req = mozContacts.find(options); + req.onsuccess = function () { + is(req.result.length, 1, "Found exactly 1 contacts."); + next(); + }; + req.onerror = onFailure; + }, + function () { + ok(true, "Deleting database"); + req = mozContacts.clear() + req.onsuccess = function () { + ok(true, "Deleted the database"); + next(); + } + req.onerror = onFailure; + }, + function () { + ok(true, "Adding a new contact with a Brazilian country code"); + createResult1 = new mozContact(prop5); + req = navigator.mozContacts.save(createResult1); + req.onsuccess = function () { + ok(createResult1.id, "The contact now has an ID."); + sample_id1 = createResult1.id; + next(); + }; + req.onerror = onFailure; + }, + function () { + ok(true, "Searching for international number with prefix"); + var options = {filterBy: ["tel"], + filterOp: "match", + filterValue: brazilianNumber.international1}; + req = mozContacts.find(options); + req.onsuccess = function () { + ok(req.result.length == 1, "Found exactly 1 contact."); + findResult1 = req.result[0]; + ok(findResult1.id == sample_id1, "Same ID"); + next(); + }; + req.onerror = onFailure; + }, + function () { + ok(true, "Deleting database"); + req = mozContacts.clear() + req.onsuccess = function () { + ok(true, "Deleted the database"); + next(); + } + req.onerror = onFailure; + }, + function () { + ok(true, "all done!\n"); + parent.SimpleTest.finish(); + } +]; + +SpecialPowers.pushPrefEnv({ + set: [ + ["dom.phonenumber.substringmatching.BR", substringLength], + ["ril.lastKnownSimMcc", "724"] + ] +}, start_tests); +</script> +</pre> +</body> +</html>
new file mode 100644 --- /dev/null +++ b/dom/contacts/tests/file_contacts_substringmatchingCL.html @@ -0,0 +1,207 @@ +<!DOCTYPE html> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=877302 +--> +<head> + <title>Test for Bug 949537 substring matching for WebContacts</title> + <script type="text/javascript" src="/MochiKit/MochiKit.js"></script> + <script type="text/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=949537">Mozilla Bug 949537</a> +<p id="display"></p> +<div id="content" style="display: none"> + +</div> +<pre id="test"> +<script type="text/javascript;version=1.8" src="http://mochi.test:8888/tests/dom/contacts/tests/shared.js"></script> +<script class="testbody" type="text/javascript"> +"use strict"; + +var ok = parent.ok; +var ise = parent.ise; + +var landlineNumber = "+56 2 27654321"; + +var number = { + local: "87654321", + international: "+56 9 87654321" +}; + +var properties = { + name: ["Testname2"], + tel: [{value: number.international}] +}; + +var req; +var steps = [ + function () { + ok(true, "Adding a contact with a Chilean number"); + createResult1 = new mozContact(properties); + req = navigator.mozContacts.save(createResult1); + req.onsuccess = function () { + ok(createResult1.id, "The contact now has an ID."); + sample_id1 = createResult1.id; + next(); + }; + req.onerror = onFailure; + }, + function () { + ok(true, "Searching for Chilean number with prefix"); + req = mozContacts.find({ + filterBy: ["tel"], + filterOp: "match", + filterValue: number.international + }); + req.onsuccess = function () { + is(req.result.length, 1, "Found exactly 1 contact."); + findResult1 = req.result[0]; + is(findResult1.id, sample_id1, "Same ID"); + next(); + }; + req.onerror = onFailure; + }, + function () { + ok(true, "Searching for Chilean number using local number"); + req = mozContacts.find({ + filterBy: ["tel"], + filterOp: "match", + filterValue: number.local + }); + req.onsuccess = function () { + is(req.result.length, 1, "Found 0 contacts."); + next(); + }; + req.onerror = onFailure; + }, + + clearDatabase, + + function () { + ok(true, "Adding contact with mobile number"); + createResult1 = new mozContact({tel: [{value: number.international}]}); + req = navigator.mozContacts.save(createResult1); + req.onsuccess = function () { + ok(createResult1.id, "The contact now has an ID."); + sample_id1 = createResult1.id; + next(); + }; + req.onerror = onFailure; + }, + function () { + ok(true, "Retrieving all contacts"); + req = mozContacts.find({}); + req.onsuccess = function () { + is(req.result.length, 1, "One contact."); + findResult1 = req.result[0]; + next(); + }; + req.onerror = onFailure; + }, + function () { + ok(true, "Retrieving by last 8 digits"); + req = mozContacts.find({ + filterBy: ["tel"], + filterOp: "match", + filterValue: number.international.slice(-8) + }); + req.onsuccess = function () { + is(req.result.length, 1, "Found exactly 1 contact."); + findResult1 = req.result[0]; + is(findResult1.id, sample_id1, "Same ID"); + is(findResult1.tel[0].value, number.international, "Same Value"); + next(); + }; + req.onerror = onFailure; + }, + function () { + ok(true, "Retrieving by last 9 digits"); + req = mozContacts.find({ + filterBy: ["tel"], + filterOp: "match", + filterValue: number.international.slice(-9) + }); + req.onsuccess = function () { + is(req.result.length, 1, "Found exactly 1 contact."); + findResult1 = req.result[0]; + is(findResult1.id, sample_id1, "Same ID"); + is(findResult1.tel[0].value, number.international, "Same Value"); + next(); + }; + req.onerror = onFailure; + }, + function () { + ok(true, "Retrieving by last 6 digits"); + req = mozContacts.find({ + filterBy: ["tel"], + filterOp: "match", + filterValue: number.international.slice(-6) + }); + req.onsuccess = function () { + is(req.result.length, 0, "Found exactly zero contacts."); + next(); + }; + req.onerror = onFailure; + }, + + clearDatabase, + + function () { + ok(true, "Adding contact with landline number"); + createResult1 = new mozContact({tel: [{value: landlineNumber}]}); + req = navigator.mozContacts.save(createResult1); + req.onsuccess = function () { + ok(createResult1.id, "The contact now has an ID."); + sample_id1 = createResult1.id; + next(); + }; + req.onerror = onFailure; + }, + function () { + ok(true, "Retrieving all contacts"); + req = mozContacts.find({}); + req.onsuccess = function () { + is(req.result.length, 1, "One contact."); + findResult1 = req.result[0]; + next(); + }; + req.onerror = onFailure; + }, + function () { + ok(true, "Retrieving by last 7 digits (local number) with landline calling prefix"); + req = mozContacts.find({ + filterBy: ["tel"], + filterOp: "match", + filterValue: "022" + landlineNumber.slice(-7) + }); + req.onsuccess = function () { + is(req.result.length, 1, "Found exactly 1 contact."); + findResult1 = req.result[0]; + is(findResult1.id, sample_id1, "Same ID"); + is(findResult1.tel[0].value, landlineNumber, "Same Value"); + next(); + }; + req.onerror = onFailure; + }, + + clearDatabase, + + function () { + ok(true, "all done!\n"); + parent.SimpleTest.finish(); + } +]; + +SpecialPowers.pushPrefEnv({ + set: [ + ["dom.phonenumber.substringmatching.CL", 8], + ["ril.lastKnownSimMcc", "730"] + ] +}, start_tests); +</script> +</pre> +</body> +</html>
new file mode 100644 --- /dev/null +++ b/dom/contacts/tests/file_contacts_substringmatchingVE.html @@ -0,0 +1,135 @@ +<!DOCTYPE html> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=877302 +--> +<head> + <title>Test for Bug 877302 substring matching for WebContacts</title> + <script type="text/javascript" src="/MochiKit/MochiKit.js"></script> + <script type="text/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=877302">Mozilla Bug 877302</a> +<p id="display"></p> +<div id="content" style="display: none"> + +</div> +<pre id="test"> +<script type="text/javascript;version=1.8" src="http://mochi.test:8888/tests/dom/contacts/tests/shared.js"></script> +<script class="testbody" type="text/javascript"> +"use strict"; + +var ok = parent.ok; +var is = parent.is; + +var prop = { + tel: [{value: "7932012345" }, {value: "7704143727591"}] +}; + +var prop2 = { + tel: [{value: "7932012345" }, {value: "+58 212 5551212"}] +}; + +var req; +var steps = [ + function () { + ok(true, "Deleting database"); + req = mozContacts.clear() + req.onsuccess = function () { + ok(true, "Deleted the database"); + next(); + } + req.onerror = onFailure; + }, + function () { + ok(true, "Adding contact"); + createResult1 = new mozContact(prop); + req = navigator.mozContacts.save(createResult1); + req.onsuccess = function () { + ok(createResult1.id, "The contact now has an ID."); + sample_id1 = createResult1.id; + next(); + }; + req.onerror = onFailure; + }, + function () { + ok(true, "Retrieving all contacts"); + req = mozContacts.find({}); + req.onsuccess = function () { + is(req.result.length, 1, "One contact."); + findResult1 = req.result[0]; + next(); + }; + req.onerror = onFailure; + }, + function () { + ok(true, "Retrieving by substring 1"); + var length = prop.tel[0].value.length; + var num = "04143727591" + var options = {filterBy: ["tel"], + filterOp: "match", + filterValue: num}; + req = mozContacts.find(options); + req.onsuccess = function () { + is(req.result.length, 1, "Found exactly 1 contact."); + findResult1 = req.result[0]; + ok(findResult1.id == sample_id1, "Same ID"); + is(findResult1.tel[1].value, "7704143727591", "Same Value"); + next(); + }; + req.onerror = onFailure; + }, + function () { + ok(true, "Adding contact"); + createResult1 = new mozContact(prop2); + req = navigator.mozContacts.save(createResult1); + req.onsuccess = function () { + ok(createResult1.id, "The contact now has an ID."); + sample_id1 = createResult1.id; + next(); + }; + req.onerror = onFailure; + }, + function () { + ok(true, "Retrieving by substring 2"); + var num = "5551212"; + var options = {filterBy: ["tel"], + filterOp: "match", + filterValue: num}; + req = mozContacts.find(options); + req.onsuccess = function () { + is(req.result.length, 1, "Found exactly 1 contact."); + findResult1 = req.result[0]; + ok(findResult1.id == sample_id1, "Same ID"); + is(findResult1.tel[1].value, "+58 212 5551212", "Same Value"); + next(); + }; + req.onerror = onFailure; + }, + function () { + ok(true, "Deleting database"); + req = mozContacts.clear() + req.onsuccess = function () { + ok(true, "Deleted the database"); + next(); + } + req.onerror = onFailure; + }, + function () { + ok(true, "all done!\n"); + parent.SimpleTest.finish(); + } +]; + +SpecialPowers.pushPrefEnv({ + set: [ + ["dom.phonenumber.substringmatching.VE", 7], + ["ril.lastKnownSimMcc", "734"] + ] +}, start_tests); +</script> +</pre> +</body> +</html>
new file mode 100644 --- /dev/null +++ b/dom/contacts/tests/file_migration.html @@ -0,0 +1,197 @@ +<!DOCTYPE html> +<html> +<head> + <title>Migration tests</title> + <script type="text/javascript" src="/MochiKit/MochiKit.js"></script> + <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> +</head> +<body> +<h1>migration tests</h1> +<p id="display"></p> +<div id="content" style="display: none"> + +</div> +<pre id="test"> +<script type="text/javascript;version=1.8" src="shared.js"></script> +<script class="testbody" type="text/javascript"> +"use strict"; + +var ok = parent.ok; +var ise = parent.ise; + +var backend, contactsCount, allContacts; +function loadChromeScript() { + var url = SimpleTest.getTestFileURL("test_migration_chrome.js"); + backend = SpecialPowers.loadChromeScript(url); +} + +function addBackendEvents() { + backend.addMessageListener("createDB.success", function(count) { + contactsCount = count; + ok(true, "Created the database"); + next(); + }); + backend.addMessageListener("createDB.error", function(err) { + ok(false, err); + next(); + }); + + backend.addMessageListener("deleteDB.success", function() { + ok(true, "Deleted the database"); + next(); + }); + backend.addMessageListener("deleteDB.error", function(err) { + ok(false, err); + next(); + }); +} + +function createDB(version) { + info("Will create the DB at version " + version); + backend.sendAsyncMessage("createDB", version); +} + +function deleteDB() { + info("Will delete the DB."); + backend.sendAsyncMessage("deleteDB"); +} + +var steps = [ + function setupChromeScript() { + loadChromeScript(); + addBackendEvents(); + next(); + }, + + deleteDB, // let's be sure the DB does not exist yet + createDB.bind(null, 12), + + function testAccessMozContacts() { + info("Checking we have the right number of contacts: " + contactsCount); + var req = mozContacts.getCount(); + req.onsuccess = function onsuccess() { + ok(true, "Could access the mozContacts API"); + is(this.result, contactsCount, "Contacts count is correct"); + next(); + }; + + req.onerror = function onerror() { + ok(false, "Couldn't access the mozContacts API"); + next(); + }; + }, + + function testRetrieveAllContacts() { + /* if the migration does not work right, either we'll have an error, or the + contacts won't be migrated properly and thus will fail WebIDL conversion, + which will manifest as a timeout */ + info("Checking the contacts are corrected to obey WebIDL constraints. (upgrades 14 to 17)"); + var req = mozContacts.find(); + req.onsuccess = function onsuccess() { + if (this.result) { + is(this.result.length, contactsCount, "Contacts array length is correct"); + allContacts = this.result; + next(); + } else { + ok(false, "Could access the mozContacts API but got no contacts!"); + next(); + } + }; + + req.onerror = function onerror() { + ok(false, "Couldn't access the mozContacts API"); + next(); + }; + }, + + function checkNameIndex() { + info("Checking name index migration (upgrades 17 to 19)."); + if (!allContacts) { + next(); + } + + var count = allContacts.length; + + function finishRequest() { + count--; + if (!count) { + next(); + } + } + + allContacts.forEach(function(contact) { + var name = contact.name && contact.name[0]; + if (!name) { + count--; + return; + } + + var req = mozContacts.find({ + filterBy: ["name"], + filterValue: name, + filterOp: "equals" + }); + + req.onsuccess = function onsuccess() { + if (this.result) { + info("Found contact '" + name + "', checking it's the correct one."); + checkContacts(this.result[0], contact); + } else { + ok(false, "Could not find contact with name '" + name + "'"); + } + + finishRequest(); + }; + + req.onerror = function onerror() { + ok(false, "Error while finding contact with name '" + name + "'!"); + finishRequest(); + } + }); + + if (!count) { + ok(false, "No contact had a name, this is unexpected."); + next(); + } + }, + + function checkSubstringMatching() { + var subject = "0004567890"; // the last 7 digits are the same that at least one contact + info("Looking for a contact matching " + subject); + var req = mozContacts.find({ + filterValue: subject, + filterOp: "match", + filterBy: ["tel"], + filterLimit: 1 + }); + + req.onsuccess = function onsuccess() { + if (this.result && this.result[0]) { + ok(true, "Found a contact with number " + this.result[0].tel[0].value); + } + next(); + }; + + req.onerror = function onerror() { + ok(false, "Error while finding contact for substring matching check!"); + next(); + }; + }, + + deleteDB, + + function finish() { + backend.destroy(); + info("all done!\n"); + parent.SimpleTest.finish(); + } +]; + +// this is the Mcc for Brazil, so that we trigger the previous pref +SpecialPowers.pushPrefEnv({"set": [["dom.phonenumber.substringmatching.BR", 7], + ["ril.lastKnownSimMcc", "724"]]}, start_tests); +</script> +</pre> +</body> +</html>
new file mode 100644 --- /dev/null +++ b/dom/contacts/tests/file_permission_denied.html @@ -0,0 +1,30 @@ +<!DOCTYPE html> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=1081873 +--> +<head> + <title>Test for Bug 1081873</title> + <script type="text/javascript" src="/MochiKit/MochiKit.js"></script> + <script type="text/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=1081873">Mozilla Bug 1081873</a> +<p id="display"></p> +<div id="content" style="display: none"> + +</div> +<pre id="test"> +<script class="testbody" type="text/javascript"> + +"use strict"; + +parent.is("mozContacts" in navigator, false, "navigator.mozContacts must be inaccessible"); +parent.SimpleTest.finish(); + +</script> +</pre> +</body> +</html>
--- a/dom/contacts/tests/mochitest.ini +++ b/dom/contacts/tests/mochitest.ini @@ -1,10 +1,24 @@ [DEFAULT] -support-files = shared.js +support-files = + shared.js + file_contacts_basics.html + file_contacts_basics2.html + file_contacts_blobs.html + file_contacts_events.html + file_contacts_getall.html + file_contacts_getall2.html + file_contacts_international.html + file_contacts_substringmatching.html + file_contacts_substringmatchingVE.html + file_contacts_substringmatchingCL.html + test_migration_chrome.js + file_migration.html + file_permission_denied.html [test_contacts_basics.html] skip-if = (toolkit == 'gonk' && debug) #debug-only failure [test_contacts_basics2.html] skip-if = (toolkit == 'gonk' && debug) || (os == 'win' && os_version == '5.1') #debug-only failure, bug 967258 on XP [test_contacts_blobs.html] skip-if = (toolkit == 'gonk' && debug) #debug-only failure [test_contacts_events.html] @@ -12,12 +26,11 @@ skip-if = (toolkit == 'gonk' && debug) # skip-if = (toolkit == 'gonk' && debug) || (toolkit == 'android' && processor == 'x86') #debug-only failure #x86 only [test_contacts_getall2.html] skip-if = (toolkit == 'gonk' && debug) #debug-only failure [test_contacts_international.html] [test_contacts_substringmatching.html] [test_contacts_substringmatchingVE.html] [test_contacts_substringmatchingCL.html] [test_migration.html] - support-files = - test_migration_chrome.js + support-files += skip-if = os == "android" [test_permission_denied.html]
--- a/dom/contacts/tests/shared.js +++ b/dom/contacts/tests/shared.js @@ -489,21 +489,15 @@ function next() { SimpleTest.waitForExplicitFinish(); function start_tests() { // Skip tests on Android < 4.0 due to test failures on tbpl (see bugs 897924 & 888891) let androidVersion = SpecialPowers.Cc['@mozilla.org/system-info;1'] .getService(SpecialPowers.Ci.nsIPropertyBag2) .getProperty('version'); if (!isAndroid || androidVersion >= 14) { - SpecialPowers.pushPermissions([ - {type: "contacts-write", allow: 1, context: document}, - {type: "contacts-read", allow: 1, context: document}, - {type: "contacts-create", allow: 1, context: document}, - ], function() { - mozContacts = navigator.mozContacts; - next(); - }); + mozContacts = navigator.mozContacts; + next(); } else { ok(true, "Skip tests on Android < 4.0 (bugs 897924 & 888891"); - SimpleTest.finish(); + parent.SimpleTest.finish(); } }
--- a/dom/contacts/tests/test_contacts_basics.html +++ b/dom/contacts/tests/test_contacts_basics.html @@ -1,784 +1,29 @@ -<!DOCTYPE html> +<!DOCTYPE HTML> <html> -<!-- -https://bugzilla.mozilla.org/show_bug.cgi?id=674720 ---> <head> - <title>Test for Bug 674720 WebContacts</title> - <script type="text/javascript" src="/MochiKit/MochiKit.js"></script> - <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script> - <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> + <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=674720">Mozilla Bug 674720</a> -<p id="display"></p> -<div id="content" style="display: none"> - -</div> +<iframe></iframe> <pre id="test"> -<script type="text/javascript;version=1.8" src="http://mochi.test:8888/tests/dom/contacts/tests/shared.js"></script> -<script class="testbody" type="text/javascript"> -"use strict"; - -var initialRev; +<script type="application/javascript"> -function checkRevision(revision, msg, then) { - var revReq = mozContacts.getRevision(); - revReq.onsuccess = function(e) { - is(e.target.result, initialRev+revision, msg); - then(); - }; - // The revision function isn't supported on Android so treat on failure as success - if (isAndroid) { - revReq.onerror = function(e) { - then(); - }; - } else { - revReq.onerror = onFailure; - } +function run_tests() { + var iframe = document.querySelector("iframe"); + iframe.src = "file_contacts_basics.html"; } -var req; - -var steps = [ - function() { - req = mozContacts.getRevision(); - req.onsuccess = function(e) { - initialRev = e.target.result; - next(); - }; - - // Android does not support the revision function. Treat errors as success. - if (isAndroid) { - req.onerror = function(e) { - initialRev = 0; - next(); - }; - } else { - req.onerror = onFailure; - } - }, - function () { - ok(true, "Deleting database"); - checkRevision(0, "Initial revision is 0", function() { - req = mozContacts.clear(); - req.onsuccess = function () { - ok(true, "Deleted the database"); - checkCount(0, "No contacts after clear", function() { - checkRevision(1, "Revision was incremented on clear", next); - }); - }; - req.onerror = onFailure; - }); - }, - function () { - ok(true, "Retrieving all contacts"); - req = mozContacts.find(defaultOptions); - req.onsuccess = function () { - is(req.result.length, 0, "Empty database."); - checkRevision(1, "Revision was not incremented on find", next); - }; - req.onerror = onFailure; - }, - function () { - ok(true, "Adding empty contact"); - createResult1 = new mozContact({}); - req = navigator.mozContacts.save(createResult1); - req.onsuccess = function () { - ok(createResult1.id, "The contact now has an ID."); - sample_id1 = createResult1.id; - checkCount(1, "1 contact after adding empty contact", function() { - checkRevision(2, "Revision was incremented on save", next); - }); - }; - req.onerror = onFailure; - }, - function () { - ok(true, "Retrieving all contacts"); - req = mozContacts.find(defaultOptions); - req.onsuccess = function () { - is(req.result.length, 1, "One contact."); - findResult1 = req.result[0]; - next(); - }; - req.onerror = onFailure; - }, - function () { - ok(true, "Deleting empty contact"); - req = navigator.mozContacts.remove(findResult1); - req.onsuccess = function () { - var req2 = mozContacts.find(defaultOptions); - req2.onsuccess = function () { - is(req2.result.length, 0, "Empty Database."); - clearTemps(); - checkRevision(3, "Revision was incremented on remove", next); - } - req2.onerror = onFailure; - } - req.onerror = onFailure; - }, - function () { - ok(true, "Adding a new contact1"); - createResult1 = new mozContact(properties1); - - mozContacts.oncontactchange = function(event) { - is(event.contactID, createResult1.id, "Same contactID"); - is(event.reason, "create", "Same reason"); - next(); - } - - req = navigator.mozContacts.save(createResult1); - req.onsuccess = function () { - ok(createResult1.id, "The contact now has an ID."); - sample_id1 = createResult1.id; - checkContacts(createResult1, properties1); - }; - req.onerror = onFailure; - }, - function () { - ok(true, "Retrieving by substring 1"); - var options = {filterBy: ["givenName"], - filterOp: "startsWith", - filterValue: properties1.givenName[1].substring(0,3)}; - req = mozContacts.find(options); - req.onsuccess = function () { - is(req.result.length, 1, "Found exactly 1 contact."); - findResult1 = req.result[0]; - ok(findResult1.id == sample_id1, "Same ID"); - checkContacts(createResult1, properties1); - // Some manual testing. Testint the testfunctions - // tel: [{type: ["work"], value: "123456", carrier: "testCarrier"} , {type: ["home", "fax"], value: "+55 (31) 9876-3456"}], - is(findResult1.tel[0].carrier, "testCarrier", "Same Carrier"); - is(String(findResult1.tel[0].type), "work", "Same type"); - is(findResult1.tel[0].value, "123456", "Same Value"); - is(findResult1.tel[1].type[1], "fax", "Same type"); - is(findResult1.tel[1].value, "+55 (31) 9876-3456", "Same Value"); - - is(findResult1.adr[0].countryName, "country 1", "Same country"); +SimpleTest.waitForExplicitFinish(); +onload = function() { + SpecialPowers.pushPermissions([ + {type: "contacts-read", allow: true, context: document}, + {type: "contacts-write", allow: true, context: document}, + {type: "contacts-create", allow: true, context: document}, + ], run_tests); +}; - // email: [{type: ["work"], value: "x@y.com"}] - is(String(findResult1.email[0].type), "work", "Same Type"); - is(findResult1.email[0].value, "x@y.com", "Same Value"); - next(); - }; - req.onerror = onFailure; - }, - function () { - ok(true, "Searching for exact email"); - var options = {filterBy: ["email"], - filterOp: "equals", - filterValue: properties1.email[0].value}; - req = mozContacts.find(options); - req.onsuccess = function () { - is(req.result.length, 1, "Found exactly 1 contact."); - findResult1 = req.result[0]; - ok(findResult1.id == sample_id1, "Same ID"); - checkContacts(findResult1, createResult1); - next(); - }; - req.onerror = onFailure; - }, - function () { - ok(true, "Retrieving by substring and update"); - mozContacts.oncontactchange = function(event) { - is(event.contactID, findResult1.id, "Same contactID"); - is(event.reason, "update", "Same reason"); - } - var options = {filterBy: ["givenName"], - filterOp: "startsWith", - filterValue: properties1.givenName[0].substring(0,3)}; - req = mozContacts.find(options); - req.onsuccess = function () { - is(req.result.length, 1, "Found exactly 1 contact."); - findResult1 = req.result[0]; - findResult1.jobTitle = ["new Job"]; - ok(findResult1.id == sample_id1, "Same ID"); - checkContacts(createResult1, properties1); - next(); - }; - req.onerror = onFailure; - }, - function () { - ok(true, "Adding a new contact"); - mozContacts.oncontactchange = function(event) { - is(event.contactID, createResult2.id, "Same contactID"); - is(event.reason, "create", "Same reason"); - } - createResult2 = new mozContact({name: ["newName"]}); - req = navigator.mozContacts.save(createResult2); - req.onsuccess = function () { - ok(createResult2.id, "The contact now has an ID."); - next(); - }; - req.onerror = onFailure; - }, - function () { - ok(true, "Retrieving by substring 2"); - var options = {filterBy: ["givenName"], - filterOp: "startsWith", - filterValue: properties1.givenName[0].substring(0,3)}; - req = mozContacts.find(options); - req.onsuccess = function () { - is(req.result.length, 1, "Found exactly 1 contact."); - findResult1 = req.result[0]; - checkContacts(createResult1, findResult1); - next(); - }; - req.onerror = onFailure; - }, - function() { - ok(true, "Retrieving by name equality 1"); - var options = {filterBy: ["name"], - filterOp: "equals", - filterValue: properties1.name[0]}; - req = mozContacts.find(options); - req.onsuccess = function () { - is(req.result.length, 1, "Found exactly 1 contact."); - findResult1 = req.result[0]; - checkContacts(createResult1, findResult1); - next(); - }; - req.onerror = onFailure; - }, - function() { - ok(true, "Retrieving by name equality 2"); - var options = {filterBy: ["name"], - filterOp: "equals", - filterValue: properties1.name[1]}; - req = mozContacts.find(options); - req.onsuccess = function () { - is(req.result.length, 1, "Found exactly 1 contact."); - findResult1 = req.result[0]; - checkContacts(createResult1, findResult1); - next(); - }; - req.onerror = onFailure; - }, - function() { - ok(true, "Retrieving by name substring 1"); - var options = {filterBy: ["name"], - filterOp: "startsWith", - filterValue: properties1.name[0].substring(0,3).toLowerCase()}; - req = mozContacts.find(options); - req.onsuccess = function () { - is(req.result.length, 1, "Found exactly 1 contact."); - findResult1 = req.result[0]; - checkContacts(createResult1, findResult1); - next(); - }; - req.onerror = onFailure; - }, - function() { - ok(true, "Retrieving by name substring 2"); - var options = {filterBy: ["name"], - filterOp: "startsWith", - filterValue: properties1.name[1].substring(0,3).toLowerCase()}; - req = mozContacts.find(options); - req.onsuccess = function () { - is(req.result.length, 1, "Found exactly 1 contact."); - findResult1 = req.result[0]; - checkContacts(createResult1, findResult1); - next(); - }; - req.onerror = onFailure; - }, - function () { - ok(true, "Remove contact1"); - mozContacts.oncontactchange = function(event) { - is(event.contactID, createResult1.id, "Same contactID"); - is(event.reason, "remove", "Same reason"); - } - req = navigator.mozContacts.remove(createResult1); - req.onsuccess = function () { - next(); - }; - req.onerror = onFailure; - }, - function () { - ok(true, "Retrieving by substring 3"); - var options = {filterBy: ["givenName"], - filterOp: "startsWith", - filterValue: properties1.givenName[1].substring(0,3)}; - req = mozContacts.find(options); - req.onsuccess = function () { - is(req.result.length, 0, "Found no contact."); - next(); - }; - req.onerror = onFailure; - }, - function () { - ok(true, "Remove contact2"); - mozContacts.oncontactchange = function(event) { - is(event.contactID, createResult2.id, "Same contactID"); - is(event.reason, "remove", "Same reason"); - } - req = navigator.mozContacts.remove(createResult2); - req.onsuccess = function () { - next(); - }; - req.onerror = onFailure; - }, - function () { - ok(true, "Retrieving by substring 4"); - var options = {filterBy: ["givenName"], - filterOp: "startsWith", - filterValue: properties1.givenName[1].substring(0,3)}; - req = mozContacts.find(options); - req.onsuccess = function () { - is(req.result.length, 0, "Found no contact."); - next(); - }; - req.onerror = onFailure; - }, - function () { - ok(true, "Deleting database"); - mozContacts.oncontactchange = function(event) { - is(event.contactID, "undefined", "Same contactID"); - is(event.reason, "remove", "Same reason"); - } - req = mozContacts.clear(); - req.onsuccess = function () { - ok(true, "Deleted the database"); - next(); - }; - req.onerror = onFailure; - }, - function () { - ok(true, "Adding a new contact with properties1"); - createResult1 = new mozContact(properties1); - mozContacts.oncontactchange = null; - req = navigator.mozContacts.save(createResult1); - req.onsuccess = function () { - ok(createResult1.id, "The contact now has an ID."); - sample_id1 = createResult1.id; - checkContacts(createResult1, properties1); - next(); - }; - req.onerror = onFailure; - }, - function () { - ok(true, "Retrieving by substring tel1"); - var options = {filterBy: ["tel"], - filterOp: "contains", - filterValue: properties1.tel[1].value.substring(2,5)}; - req = mozContacts.find(options); - req.onsuccess = function () { - is(req.result.length, 1, "Found exactly 1 contact."); - findResult1 = req.result[0]; - ok(findResult1.id == sample_id1, "Same ID"); - checkContacts(createResult1, properties1); - next(); - }; - req.onerror = onFailure; - }, - function () { - ok(true, "Retrieving by tel exact"); - var options = {filterBy: ["tel"], - filterOp: "equals", - filterValue: "+55 319 8 7 6 3456"}; - req = mozContacts.find(options); - req.onsuccess = function () { - is(req.result.length, 1, "Found exactly 1 contact."); - findResult1 = req.result[0]; - ok(findResult1.id == sample_id1, "Same ID"); - checkContacts(createResult1, properties1); - next(); - }; - req.onerror = onFailure; - }, - function () { - ok(true, "Retrieving by tel exact with substring"); - var options = {filterBy: ["tel"], - filterOp: "equals", - filterValue: "3456"}; - req = mozContacts.find(options); - req.onsuccess = function () { - is(req.result.length, 0, "Found no contacts."); - next(); - }; - req.onerror = onFailure; - }, - function () { - ok(true, "Retrieving by tel exact with substring"); - var options = {filterBy: ["tel"], - filterOp: "equals", - filterValue: "+55 (31)"}; - req = mozContacts.find(options); - req.onsuccess = function () { - is(req.result.length, 0, "Found no contacts."); - next(); - }; - req.onerror = onFailure; - }, - function () { - ok(true, "Retrieving by tel match national number"); - var options = {filterBy: ["tel"], - filterOp: "match", - filterValue: "3198763456"}; - req = mozContacts.find(options); - req.onsuccess = function () { - is(req.result.length, 1, "Found exactly 1 contact."); - findResult1 = req.result[0]; - ok(findResult1.id == sample_id1, "Same ID"); - checkContacts(createResult1, properties1); - next(); - }; - req.onerror = onFailure; - }, - function () { - ok(true, "Retrieving by tel match national format"); - var options = {filterBy: ["tel"], - filterOp: "match", - filterValue: "0451 491934"}; - req = mozContacts.find(options); - req.onsuccess = function () { - is(req.result.length, 1, "Found exactly 1 contact."); - findResult1 = req.result[0]; - ok(findResult1.id == sample_id1, "Same ID"); - checkContacts(createResult1, properties1); - next(); - }; - req.onerror = onFailure; - }, - function () { - ok(true, "Retrieving by tel match entered number"); - var options = {filterBy: ["tel"], - filterOp: "match", - filterValue: "123456"}; - req = mozContacts.find(options); - req.onsuccess = function () { - is(req.result.length, 1, "Found exactly 1 contact."); - findResult1 = req.result[0]; - ok(findResult1.id == sample_id1, "Same ID"); - checkContacts(createResult1, properties1); - next(); - }; - req.onerror = onFailure; - }, - function () { - ok(true, "Retrieving by tel match international number"); - var options = {filterBy: ["tel"], - filterOp: "match", - filterValue: "+55 31 98763456"}; - req = mozContacts.find(options); - req.onsuccess = function () { - is(req.result.length, 1, "Found exactly 1 contact."); - findResult1 = req.result[0]; - ok(findResult1.id == sample_id1, "Same ID"); - checkContacts(createResult1, properties1); - next(); - }; - req.onerror = onFailure; - }, - function () { - ok(true, "Retrieving by match with field other than tel"); - var options = {filterBy: ["givenName"], - filterOp: "match", - filterValue: "my friends call me 555-4040"}; - req = mozContacts.find(options); - req.onsuccess = onUnwantedSuccess; - req.onerror = function() { - ok(true, "Failed"); - next(); - } - }, - function () { - ok(true, "Retrieving by substring tel2"); - var options = {filterBy: ["tel"], - filterOp: "startsWith", - filterValue: "9876"}; - req = mozContacts.find(options); - req.onsuccess = function () { - is(req.result.length, 1, "Found exactly 1 contact."); - findResult1 = req.result[0]; - ok(findResult1.id == sample_id1, "Same ID"); - checkContacts(createResult1, properties1); - next(); - }; - req.onerror = onFailure; - }, - function () { - ok(true, "Retrieving by substring tel3"); - var options = {filterBy: ["tel"], - filterOp: "startsWith", - filterValue: "98763456"}; - req = mozContacts.find(options); - req.onsuccess = function () { - is(req.result.length, 1, "Found exactly 1 contact."); - findResult1 = req.result[0]; - ok(findResult1.id == sample_id1, "Same ID"); - checkContacts(createResult1, properties1); - next(); - }; - req.onerror = onFailure; - }, - function () { - ok(true, "Retrieving by substring 5"); - var options = {filterBy: ["givenName"], - filterOp: "startsWith", - filterValue: properties1.givenName[0].substring(0,3)}; - req = mozContacts.find(options); - req.onsuccess = function () { - is(req.result.length, 1, "Found exactly 1 contact."); - findResult1 = req.result[0]; - ok(findResult1.id == sample_id1, "Same ID"); - checkContacts(createResult1, properties1); - next(); - }; - req.onerror = onFailure; - }, - function () { - ok(true, "Retrieving by substring 6"); - var options = {filterBy: ["familyName", "givenName"], - filterOp: "startsWith", - filterValue: properties1.givenName[0].substring(0,3)}; - req = mozContacts.find(options); - req.onsuccess = function () { - is(req.result.length, 1, "Found exactly 1 contact."); - findResult1 = req.result[0]; - ok(findResult1.id == sample_id1, "Same ID"); - checkContacts(createResult1, properties1); - next(); - }; - req.onerror = onFailure; - }, - function () { - ok(true, "Retrieving by substring3, Testing multi entry"); - var options = {filterBy: ["givenName", "familyName"], - filterOp: "startsWith", - filterValue: properties1.familyName[1].substring(0,3).toLowerCase()}; - req = mozContacts.find(options); - req.onsuccess = function () { - is(req.result.length, 1, "Found exactly 1 contact."); - findResult1 = req.result[0]; - ok(findResult1.id == sample_id1, "Same ID"); - checkContacts(createResult1, properties1); - next(); - }; - req.onerror = onFailure; - }, - function () { - ok(true, "Retrieving all contacts"); - req = mozContacts.find(defaultOptions); - req.onsuccess = function() { - is(req.result.length, 1, "Found exactly 1 contact."); - findResult1 = req.result[0]; - ok(findResult1.id == sample_id1, "Same ID"); - checkContacts(createResult1, findResult1); - if (!isAndroid) { - ok(findResult1.updated, "Has updated field"); - ok(findResult1.published, "Has published field"); - } - next(); - } - req.onerror = onFailure; - }, - function () { - ok(true, "Modifying contact1"); - if (!findResult1) { - SpecialPowers.executeSoon(next); - } else { - findResult1.impp = properties1.impp = [{value:"phil impp"}]; - req = navigator.mozContacts.save(findResult1); - req.onsuccess = function () { - var req2 = mozContacts.find(defaultOptions); - req2.onsuccess = function() { - is(req2.result.length, 1, "Found exactly 1 contact."); - findResult2 = req2.result[0]; - ok(findResult2.id == sample_id1, "Same ID"); - checkContacts(findResult2, properties1); - is(findResult2.impp.length, 1, "Found exactly 1 IMS info."); - next(); - }; - req2.onerror = onFailure; - }; - req.onerror = onFailure; - } - }, - function() { - // Android does not support published/updated fields. Skip this. - if (isAndroid) { - next(); - return; - } - - ok(true, "Saving old contact, should abort!"); - req = mozContacts.save(createResult1); - req.onsuccess = onUnwantedSuccess; - req.onerror = function() { ok(true, "Successfully declined updating old contact!"); next(); }; - }, - function () { - ok(true, "Retrieving a specific contact by ID"); - var options = {filterBy: ["id"], - filterOp: "equals", - filterValue: sample_id1}; - req = mozContacts.find(options); - req.onsuccess = function () { - is(req.result.length, 1, "Found exactly 1 contact."); - findResult1 = req.result[0]; - ok(findResult1.id == sample_id1, "Same ID"); - checkContacts(findResult1, properties1); - next(); - }; - req.onerror = onFailure; - }, - function () { - ok(true, "Retrieving a specific contact by givenName"); - var options = {filterBy: ["givenName"], - filterOp: "equals", - filterValue: properties1.givenName[0]}; - req = mozContacts.find(options); - req.onsuccess = function () { - is(req.result.length, 1, "Found exactly 1 contact."); - findResult1 = req.result[0]; - ok(findResult1.id == sample_id1, "Same ID"); - checkContacts(findResult1, properties1); - next(); - } - req.onerror = onFailure; - }, - function () { - ok(true, "Modifying contact2"); - if (!findResult1) { - SpecialPowers.executeSoon(next); - } else { - findResult1.impp = properties1.impp = [{value: "phil impp"}]; - req = mozContacts.save(findResult1); - req.onsuccess = function () { - var req2 = mozContacts.find(defaultOptions); - req2.onsuccess = function () { - is(req2.result.length, 1, "Found exactly 1 contact."); - findResult1 = req2.result[0]; - ok(findResult1.id == sample_id1, "Same ID"); - checkContacts(findResult1, properties1); - is(findResult1.impp.length, 1, "Found exactly 1 IMS info."); - next(); - } - req2.onerror = onFailure; - }; - req.onerror = onFailure; - } - }, - function () { - ok(true, "Searching contacts by query"); - var options = {filterBy: ["givenName", "email"], - filterOp: "startsWith", - filterValue: properties1.givenName[0].substring(0,4)}; - req = mozContacts.find(options); - req.onsuccess = function () { - is(req.result.length, 1, "Found exactly 1 contact."); - findResult1 = req.result[0]; - ok(findResult1.id == sample_id1, "Same ID"); - checkContacts(findResult1, properties1); - next(); - }; - req.onerror = onFailure; - }, - function () { - ok(true, "Searching contacts by query"); - var options = {filterBy: ["givenName", "email"], - filterOp: "startsWith", - filterValue: properties1.givenName[0]}; - req = mozContacts.find(options); - req.onsuccess = function () { - is(req.result.length, 1, "Found exactly 1 contact."); - findResult1 = req.result[0]; - ok(findResult1.id == sample_id1, "Same ID"); - checkContacts(findResult1, properties1); - next(); - }; - req.onerror = onFailure; - }, - function () { - ok(true, "Searching contacts with multiple indices"); - var options = {filterBy: ["email", "givenName"], - filterOp: "equals", - filterValue: properties1.givenName[1]}; - req = mozContacts.find(options); - req.onsuccess = function () { - is(req.result.length, 1, "Found exactly 1 contact."); - findResult1 = req.result[0]; - ok(findResult1.id == sample_id1, "Same ID"); - checkContacts(findResult1, properties1); - next(); - }; - req.onerror = onFailure; - }, - function () { - ok(true, "Modifying contact3"); - if (!findResult1) { - SpecialPowers.executeSoon(next); - } else { - findResult1.email = [{value: properties1.nickname}]; - findResult1.nickname = ["TEST"]; - var newContact = new mozContact(findResult1); - req = mozContacts.save(newContact); - req.onsuccess = function () { - var options = {filterBy: ["email", "givenName"], - filterOp: "startsWith", - filterValue: properties1.givenName[0]}; - // One contact has it in nickname and the other in email - var req2 = mozContacts.find(options); - req2.onsuccess = function () { - is(req2.result.length, 2, "Found exactly 2 contacts."); - ok(req2.result[0].id != req2.result[1].id, "Different ID"); - next(); - } - req2.onerror = onFailure; - }; - req.onerror = onFailure; - } - }, - function () { - ok(true, "Deleting contact" + findResult1); - req = mozContacts.remove(findResult1); - req.onsuccess = function () { - var req2 = mozContacts.find(defaultOptions); - req2.onsuccess = function () { - is(req2.result.length, 1, "One contact left."); - findResult1 = req2.result[0]; - next(); - } - req2.onerror = onFailure; - } - req.onerror = onFailure; - }, - function () { - ok(true, "Deleting database"); - req = mozContacts.remove(findResult1); - req.onsuccess = function () { - clearTemps(); - next(); - }; - req.onerror = onFailure; - }, - function() { - ok(true, "Test JSON.stringify output for mozContact objects"); - var json = JSON.parse(JSON.stringify(new mozContact(properties1))); - checkContacts(json, properties1); - next(); - }, - function() { - ok(true, "Test slice"); - var c = new mozContact(); - c.email = [{ type: ["foo"], value: "bar@baz" }] - var arr = c.email; - is(arr[0].value, "bar@baz", "Should have the right value"); - arr = arr.slice(); - is(arr[0].value, "bar@baz", "Should have the right value after slicing"); - next(); - }, - function () { - ok(true, "all done!\n"); - clearTemps(); - - SimpleTest.finish(); - } -]; - -start_tests(); </script> </pre> </body> </html>
--- a/dom/contacts/tests/test_contacts_basics2.html +++ b/dom/contacts/tests/test_contacts_basics2.html @@ -1,1149 +1,29 @@ -<!DOCTYPE html> +<!DOCTYPE HTML> <html> -<!-- -https://bugzilla.mozilla.org/show_bug.cgi?id=674720 ---> <head> - <title>Test for Bug 674720 WebContacts</title> - <script type="text/javascript" src="/MochiKit/MochiKit.js"></script> - <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script> - <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> + <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=674720">Mozilla Bug 674720</a> -<p id="display"></p> -<div id="content" style="display: none"> - -</div> +<iframe></iframe> <pre id="test"> -<script type="text/javascript;version=1.8" src="http://mochi.test:8888/tests/dom/contacts/tests/shared.js"></script> -<script class="testbody" type="text/javascript"> -"use strict"; - -var req; - -var steps = [ - function () { - ok(true, "Adding a new contact"); - createResult1 = new mozContact(properties1); - req = mozContacts.save(createResult1) - req.onsuccess = function () { - ok(createResult1.id, "The contact now has an ID."); - sample_id1 = createResult1.id; - next(); - } - req.onerror = onFailure; - }, - function () { - ok(true, "Adding a new contact2"); - createResult2 = new mozContact(properties2); - req = mozContacts.save(createResult2); - req.onsuccess = function () { - ok(createResult2.id, "The contact now has an ID."); - sample_id2 = createResult2.id; - next(); - }; - req.onerror = onFailure; - }, - function () { - ok(true, "Retrieving all contacts"); - req = mozContacts.find({sortBy: "familyName"}); - req.onsuccess = function () { - is(req.result.length, 2, "Found exactly 2 contact."); - checkContacts(req.result[1], properties1); - next(); - } - req.onerror = onFailure; - }, - function () { - console.log("Searching contacts by query1"); - var options = {filterBy: ["givenName", "email"], - filterOp: "startsWith", - filterValue: properties1.givenName[0].substring(0, 4)} - req = mozContacts.find(options) - req.onsuccess = function () { - is(req.result.length, 1, "Found exactly 1 contact."); - findResult1 = req.result[0]; - ok(findResult1.id == sample_id1, "Same ID"); - checkContacts(findResult1, createResult1); - next(); - } - req.onerror = onFailure; - }, - function () { - ok(true, "Searching contacts by query2"); - var options = {filterBy: ["givenName", "email"], - filterOp: "startsWith", - filterValue: properties2.givenName[0].substring(0, 4)}; - req = mozContacts.find(options); - req.onsuccess = function () { - is(req.result.length, 1, "Found exactly 1 contact."); - findResult1 = req.result[0]; - is(findResult1.adr.length, 2, "Adr length 2"); - checkContacts(findResult1, createResult2); - next(); - } - req.onerror = onFailure; - }, - function () { - ok(true, "Searching contacts by tel"); - var options = {filterBy: ["tel"], - filterOp: "contains", - filterValue: properties2.tel[0].value.substring(3, 7)}; - req = mozContacts.find(options); - req.onsuccess = function () { - is(req.result.length, 1, "Found exactly 1 contact."); - findResult1 = req.result[0]; - ok(findResult1.id == sample_id2, "Same ID"); - checkContacts(findResult1, createResult2); - next(); - } - req.onerror = onFailure; - }, - function () { - ok(true, "Searching contacts by email"); - var options = {filterBy: ["email"], - filterOp: "startsWith", - filterValue: properties2.email[0].value.substring(0, 4)}; - req = mozContacts.find(options); - req.onsuccess = function () { - is(req.result.length, 1, "Found exactly 1 contact."); - findResult1 = req.result[0]; - ok(findResult1.id == sample_id2, "Same ID"); - checkContacts(findResult1, createResult2); - next(); - } - req.onerror = onFailure; - }, - function () { - ok(true, "Deleting database"); - req = mozContacts.clear(); - req.onsuccess = function () { - next(); - } - req.onerror = onFailure; - }, - function () { - ok(true, "Adding 20 contacts"); - for (var i=0; i<19; i++) { - createResult1 = new mozContact(properties1); - req = mozContacts.save(createResult1); - req.onsuccess = function () { - ok(createResult1.id, "The contact now has an ID."); - }; - req.onerror = onFailure; - }; - createResult1 = new mozContact(properties1); - req = mozContacts.save(createResult1); - req.onsuccess = function () { - ok(createResult1.id, "The contact now has an ID."); - checkStrArray(createResult1.name, properties1.name, "Same Name"); - checkCount(20, "20 contacts in DB", next); - }; - req.onerror = onFailure; - }, - function () { - ok(true, "Retrieving all contacts"); - req = mozContacts.find(defaultOptions); - req.onsuccess = function () { - is(req.result.length, 20, "20 Entries."); - next(); - } - req.onerror = onFailure; - }, - function () { - ok(true, "Retrieving all contacts with limit 10"); - var options = { filterLimit: 10 }; - req = mozContacts.find(options); - req.onsuccess = function () { - is(req.result.length, 10, "10 Entries."); - next(); - } - req.onerror = onFailure; - }, - function () { - ok(true, "Retrieving all contacts with limit 10 and sorted"); - var options = { filterLimit: 10, - sortBy: 'FamilyName', - sortOrder: 'descending' }; - req = mozContacts.find(options); - req.onsuccess = function () { - is(req.result.length, 10, "10 Entries."); - next(); - } - req.onerror = onFailure; - }, - function () { - ok(true, "Retrieving all contacts2"); - var options = {filterBy: ["givenName"], - filterOp: "startsWith", - filterValue: properties1.givenName[0].substring(0, 4)}; - req = mozContacts.find(options); - req.onsuccess = function () { - is(req.result.length, 20, "20 Entries."); - checkContacts(createResult1, req.result[19]); - next(); - } - req.onerror = onFailure; - }, - function () { - ok(true, "Retrieving all contacts3"); - var options = {filterBy: ["givenName", "tel", "email"], - filterOp: "startsWith", - filterValue: properties1.givenName[0].substring(0, 4)}; - req = mozContacts.find(options); - req.onsuccess = function () { - is(req.result.length, 20, "20 Entries."); - checkContacts(createResult1, req.result[10]); - next(); - } - req.onerror = onFailure; - }, - function () { - ok(true, "Deleting database"); - req = mozContacts.clear(); - req.onsuccess = function () { - next(); - } - req.onerror = onFailure; - }, - function () { - ok(true, "Testing clone contact"); - createResult1 = new mozContact(properties1); - req = mozContacts.save(createResult1); - req.onsuccess = function () { - ok(createResult1.id, "The contact now has an ID."); - checkStrArray(createResult1.name, properties1.name, "Same Name"); - next(); - } - req.onerror = onFailure; - }, - function() { - ok(true, "Testing clone contact2"); - var cloned = new mozContact(createResult1); - ok(cloned.id != createResult1.id, "Cloned contact has new ID"); - cloned.email = [{value: "new email!"}]; - cloned.givenName = ["Tom"]; - req = mozContacts.save(cloned); - req.onsuccess = function () { - ok(cloned.id, "The contact now has an ID."); - is(cloned.email[0].value, "new email!", "Same Email"); - isnot(createResult1.email[0].value, cloned.email[0].value, "Clone has different email"); - is(String(cloned.givenName), "Tom", "New Name"); - next(); - } - req.onerror = onFailure; - }, - function () { - ok(true, "Retrieving all contacts"); - var options = {filterBy: ["givenName"], - filterOp: "startsWith", - filterValue: properties2.givenName[0].substring(0, 4)}; - req = mozContacts.find(defaultOptions); - req.onsuccess = function () { - is(req.result.length, 2, "2 Entries."); - next(); - } - req.onerror = onFailure; - }, - function () { - ok(true, "Search with redundant fields should only return 1 contact"); - createResult1 = new mozContact({name: ["XXX"], - givenName: ["XXX"], - email: [{value: "XXX"}], - tel: [{value: "XXX"}] - }); - req = mozContacts.save(createResult1); - req.onsuccess = function() { - var options = {filterBy: ["givenName", "familyName"], - filterOp: "equals", - filterValue: "XXX"}; - var req2 = mozContacts.find(options); - req2.onsuccess = function() { - is(req2.result.length, 1, "1 Entry"); - next(); - } - req2.onerror = onFailure; - } - req.onerror = onFailure; - }, - function () { - ok(true, "Deleting database"); - req = mozContacts.clear() - req.onsuccess = function () { - ok(true, "Deleted the database"); - next(); - } - req.onerror = onFailure; - }, - function () { - ok(true, "Test sorting"); - createResult1 = new mozContact(c3); - req = navigator.mozContacts.save(createResult1); - req.onsuccess = function () { - ok(createResult1.id, "The contact now has an ID."); - checkContacts(c3, createResult1); - next(); - }; - req.onerror = onFailure; - }, - function () { - ok(true, "Test sorting"); - createResult1 = new mozContact(c2); - req = navigator.mozContacts.save(createResult1); - req.onsuccess = function () { - ok(createResult1.id, "The contact now has an ID."); - checkContacts(c2, createResult1); - next(); - }; - req.onerror = onFailure; - }, - function () { - ok(true, "Test sorting"); - createResult1 = new mozContact(c4); - req = navigator.mozContacts.save(createResult1); - req.onsuccess = function () { - ok(createResult1.id, "The contact now has an ID."); - checkContacts(c4, createResult1); - next(); - }; - req.onerror = onFailure; - }, - function () { - ok(true, "Test sorting"); - createResult1 = new mozContact(c1); - req = navigator.mozContacts.save(createResult1); - req.onsuccess = function () { - ok(createResult1.id, "The contact now has an ID."); - checkContacts(c1, createResult1); - next(); - }; - req.onerror = onFailure; - }, - function () { - ok(true, "Test sorting"); - var options = {sortBy: "familyName", - sortOrder: "ascending"}; - req = navigator.mozContacts.find(options); - req.onsuccess = function () { - is(req.result.length, 4, "4 results"); - checkContacts(req.result[0], c1); - checkContacts(req.result[1], c2); - checkContacts(req.result[2], c3); - checkContacts(req.result[3], c4); - next(); - }; - req.onerror = onFailure; - }, - function () { - ok(true, "Test sorting"); - var options = {sortBy: "familyName", - sortOrder: "descending"}; - req = navigator.mozContacts.find(options); - req.onsuccess = function () { - is(req.result.length, 4, "4 results"); - checkContacts(req.result[0], c4); - checkContacts(req.result[1], c3); - checkContacts(req.result[2], c2); - checkContacts(req.result[3], c1); - next(); - }; - req.onerror = onFailure; - }, - function () { - ok(true, "Test sorting"); - createResult1 = new mozContact(c5); - req = navigator.mozContacts.save(createResult1); - req.onsuccess = function () { - ok(createResult1.id, "The contact now has an ID."); - checkContacts(c5, createResult1); - next(); - }; - req.onerror = onFailure; - }, - function () { - ok(true, "Test sorting with empty string"); - var options = {sortBy: "familyName", - sortOrder: "ascending"}; - req = navigator.mozContacts.find(options); - req.onsuccess = function () { - is(req.result.length, 5, "5 results"); - checkContacts(req.result[0], c5); - checkContacts(req.result[1], c1); - checkContacts(req.result[2], c2); - checkContacts(req.result[3], c3); - checkContacts(req.result[4], c4); - next(); - }; - req.onerror = onFailure; - }, - function () { - ok(true, "Don't allow to add custom fields"); - createResult1 = new mozContact({givenName: ["customTest"], yyy: "XXX"}); - req = mozContacts.save(createResult1); - req.onsuccess = function() { - var options = {filterBy: ["givenName"], - filterOp: "equals", - filterValue: "customTest"}; - var req2 = mozContacts.find(options); - req2.onsuccess = function() { - is(req2.result.length, 1, "1 Entry"); - checkStrArray(req2.result[0].givenName, ["customTest"], "same name"); - ok(req2.result.yyy === undefined, "custom property undefined"); - next(); - } - req2.onerror = onFailure; - } - req.onerror = onFailure; - }, - function () { - ok(true, "Deleting database"); - req = mozContacts.clear() - req.onsuccess = function () { - ok(true, "Deleted the database"); - next(); - } - req.onerror = onFailure; - }, - function () { - ok(true, "Test sorting"); - createResult1 = new mozContact(c7); - req = navigator.mozContacts.save(createResult1); - req.onsuccess = function () { - ok(createResult1.id, "The contact now has an ID."); - checkContacts(c7, createResult1); - next(); - }; - req.onerror = onFailure; - }, - function () { - ok(true, "Test sorting"); - createResult1 = new mozContact(c6); - req = navigator.mozContacts.save(createResult1); - req.onsuccess = function () { - ok(createResult1.id, "The contact now has an ID."); - checkContacts(c6, createResult1); - next(); - }; - req.onerror = onFailure; - }, - function () { - ok(true, "Test sorting"); - createResult1 = new mozContact(c8); - req = navigator.mozContacts.save(createResult1); - req.onsuccess = function () { - ok(createResult1.id, "The contact now has an ID."); - checkContacts(c8, createResult1); - next(); - }; - req.onerror = onFailure; - }, - function () { - // Android does not support published/updated fields. Skip this. - if (isAndroid) { - next(); - return; - } +<script type="application/javascript"> - ok(true, "Test sorting with published"); - var options = {sortBy: "familyName", - sortOrder: "descending"}; - req = navigator.mozContacts.find(options); - req.onsuccess = function () { - is(req.result.length, 3, "3 results"); - ok(req.result[0].published < req.result[1].published, "Right sorting order"); - ok(req.result[1].published < req.result[2].published, "Right sorting order"); - next(); - }; - req.onerror = onFailure; - }, - function () { - ok(true, "Deleting database"); - req = mozContacts.clear(); - req.onsuccess = function () { - ok(true, "Deleted the database"); - next(); - } - req.onerror = onFailure; - }, - function () { - ok(true, "Adding a new contact with properties2"); - createResult2 = new mozContact(properties2); - req = mozContacts.save(createResult2); - req.onsuccess = function () { - ok(createResult2.id, "The contact now has an ID."); - sample_id2 = createResult2.id; - next(); - }; - req.onerror = onFailure; - }, - function () { - ok(true, "Test category search with startsWith"); - var options = {filterBy: ["category"], - filterOp: "startsWith", - filterValue: properties2.category[0]}; - req = mozContacts.find(options); - req.onsuccess = function () { - is(req.result.length, 1, "1 Entry."); - checkContacts(req.result[0], createResult2); - next(); - } - req.onerror = onFailure; - }, - function () { - ok(true, "Test category search with equals"); - var options = {filterBy: ["category"], - filterOp: "equals", - filterValue: properties2.category[0]}; - req = mozContacts.find(options); - req.onsuccess = function () { - is(req.result.length, 1, "1 Entry."); - checkContacts(req.result[0], createResult2); - next(); - } - req.onerror = onFailure; - }, - function () { - ok(true, "Deleting database"); - req = mozContacts.clear() - req.onsuccess = function () { - ok(true, "Deleted the database"); - next(); - } - req.onerror = onFailure; - }, - function () { - ok(true, "Adding contact for category search"); - createResult1 = new mozContact({name: ["5"], givenName: ["5"]}); - req = navigator.mozContacts.save(createResult1); - req.onsuccess = function () { - ok(createResult1.id, "The contact now has an ID."); - sample_id1 = createResult1.id; - next(); - }; - req.onerror = onFailure; - }, - function () { - ok(true, "Test category search with equals"); - var options = {filterBy: ["givenName"], - filterOp: "startsWith", - filterValue: "5"}; - req = mozContacts.find(options); - req.onsuccess = function () { - is(req.result.length, 1, "1 Entry."); - checkContacts(req.result[0], createResult1); - next(); - } - req.onerror = onFailure; - }, - function () { - ok(true, "Deleting database"); - req = mozContacts.clear() - req.onsuccess = function () { - ok(true, "Deleted the database"); - next(); - } - req.onerror = onFailure; - }, - function () { - ok(true, "Adding contact with invalid data"); - var obj = { - honorificPrefix: [], - honorificSuffix: [{foo: "bar"}], - sex: 17, - genderIdentity: 18, - email: [{type: ["foo"], value: "bar"}] - }; - obj.honorificPrefix.__defineGetter__('0',(function() { - var c = 0; - return function() { - if (c == 0) { - c++; - return "string"; - } else { - return {foo:"bar"}; - } - } - })()); - createResult1 = new mozContact(obj); - createResult1.email.push({aeiou: "abcde"}); - req = mozContacts.save(createResult1); - req.onsuccess = function () { - checkContacts(createResult1, { - honorificPrefix: ["string"], - honorificSuffix: ["[object Object]"], - sex: "17", - genderIdentity: "18", - email: [{type: ["foo"], value: "bar"}, {}] - }); - next(); - }; - }, - function () { - ok(true, "Adding contact with no number but carrier"); - createResult1 = new mozContact({ tel: [{type: ["home"], carrier: "myCarrier"} ] }); - req = navigator.mozContacts.save(createResult1); - req.onsuccess = function () { - ok(createResult1.id, "The contact now has an ID."); - next(); - }; - req.onerror = onFailure; - }, - function () { - ok(true, "Adding contact with email but no value"); - createResult1 = new mozContact({ email: [{type: ["home"]}] }); - req = navigator.mozContacts.save(createResult1); - req.onsuccess = function () { - ok(createResult1.id, "The contact now has an ID."); - next(); - }; - req.onerror = onFailure; - }, - function () { - ok(true, "Testing numbersOnly search 1"); - createResult1 = new mozContact({ name: ["aaaaaaaaa"], givenName: ["aaaaaaaaa"], tel: [{ value: "1234567890"}]}); - req = navigator.mozContacts.save(createResult1); - req.onsuccess = function () { - ok(createResult1.id, "The contact now has an ID."); - next(); - }; - req.onerror = onFailure; - }, - function () { - ok(true, "Test numbersOnly search 2"); - var options = {filterBy: ["givenName", "tel"], - filterOp: "contains", - filterValue: "a"}; - req = mozContacts.find(options); - req.onsuccess = function () { - ok(req.result.length == 1, "1 Entry."); - checkContacts(req.result[0], createResult1); - next(); - } - req.onerror = onFailure; - }, - function () { - ok(true, "Test numbersOnly search 3"); - var options = {filterBy: ["givenName", "tel"], - filterOp: "contains", - filterValue: "b"}; - req = mozContacts.find(options); - req.onsuccess = function () { - ok(req.result.length == 0, "0 Entries."); - next(); - } - req.onerror = onFailure; - }, - function () { - ok(true, "Test numbersOnly search 4"); - var options = {filterBy: ["givenName", "tel"], - filterOp: "contains", - filterValue: "1a"}; - req = mozContacts.find(options); - req.onsuccess = function () { - ok(req.result.length == 0, "0 Entries."); - next(); - } - req.onerror = onFailure; - }, - function () { - ok(true, "Test numbersOnly search 5"); - var options = {filterBy: ["givenName", "tel"], - filterOp: "contains", - filterValue: "1(23)"}; - req = mozContacts.find(options); - req.onsuccess = function () { - ok(req.result.length == 1, "1 Entry."); - next(); - } - req.onerror = onFailure; - }, - function () { - ok(true, "Test numbersOnly search 6"); - var options = {filterBy: ["givenName", "tel"], - filterOp: "contains", - filterValue: "1(23)a"}; - req = mozContacts.find(options); - req.onsuccess = function () { - ok(req.result.length == 0, "0 Entries."); - next(); - } - req.onerror = onFailure; - }, - function () { - ok(true, "Deleting database"); - req = mozContacts.clear() - req.onsuccess = function () { - ok(true, "Deleted the database"); - next(); - } - req.onerror = onFailure; - }, - function() { - ok(true, "Test that after setting array properties to scalar values the property os not a non-array") - const FIELDS = ["email","url","adr","tel","impp"]; - createResult1 = new mozContact(); - for (var prop of FIELDS) { - try { - createResult1[prop] = {type: ["foo"]}; - } catch (e) {} - ok(createResult1[prop] === null || - Array.isArray(createResult1[prop]), prop + " is array"); - } - next(); - }, - function() { - ok(true, "Undefined properties of fields should be treated correctly"); - var c = new mozContact({ - adr: [{streetAddress: undefined}], - email: [{value: undefined}], - url: [{value: undefined}], - impp: [{value: undefined}], - tel: [{value: undefined}], - }); - is(c.adr[0].streetAddress, undefined, "adr.streetAddress is undefined"); - is(c.adr[0].locality, undefined, "adr.locality is undefined"); - is(c.adr[0].pref, undefined, "adr.pref is undefined"); - is(c.email[0].value, undefined, "email.value is undefined"); - is(c.url[0].value, undefined, "url.value is undefined"); - is(c.impp[0].value, undefined, "impp.value is undefined"); - is(c.tel[0].value, undefined, "tel.value is undefined"); - next(); - }, - function() { - ok(true, "Setting array properties to an empty array should work"); - var c = new mozContact(); - function testArrayProp(prop) { - is(c[prop], null, "property is initially null"); - c[prop] = []; - ok(Array.isArray(c[prop]), "property is an array after setting"); - is(c[prop].length, 0, "property has length 0 after setting"); - } - testArrayProp("email"); - testArrayProp("adr"); - testArrayProp("tel"); - testArrayProp("impp"); - testArrayProp("url"); - next(); - }, - function() { - ok(true, "Passing a mozContact with invalid data to save() should throw"); - var c = new mozContact({ - photo: [], - tel: [] - }); - c.photo.push({}); - SimpleTest.doesThrow(()=>navigator.mozContacts.save(c), "Invalid data in Blob array"); - c.tel.push(123); - SimpleTest.doesThrow(()=>navigator.mozContacts.save(c), "Invalid data in dictionary array"); - next(); - }, - function() { - ok(true, "Inline changes to array properties should be seen by save"); - var c = new mozContact({ - name: [], - familyName: [], - givenName: [], - phoneticFamilyName: [], - phoneticGivenName: [], - nickname: [], - tel: [], - adr: [], - email: [] - }); - for (var prop of Object.getOwnPropertyNames(properties1)) { - if (!Array.isArray(properties1[prop])) { - continue; - } - for (var i = 0; i < properties1[prop].length; ++i) { - c[prop].push(properties1[prop][i]); - } - } - req = navigator.mozContacts.save(c); - req.onsuccess = function() { - req = navigator.mozContacts.find(defaultOptions); - req.onsuccess = function() { - is(req.result.length, 1, "Got 1 contact"); - checkContacts(req.result[0], properties1); - next(); - }; - req.onerror = onFailure; - }; - req.onerror = onFailure; - }, - clearDatabase, - function() { - ok(true, "mozContact.init deprecation message"); - var c = new mozContact(); - SimpleTest.monitorConsole(next, [ - { errorMessage: "mozContact.init is DEPRECATED. Use the mozContact constructor instead. " + - "See https://developer.mozilla.org/docs/WebAPI/Contacts for details." } - ], /* forbidUnexpectedMsgs */ true); - c.init({name: ["Bar"]}); - c.init({name: ["Bar"]}); - SimpleTest.endMonitorConsole(); - }, - function() { - ok(true, "mozContact.init works as expected"); - var c = new mozContact({name: ["Foo"]}); - c.init({name: ["Bar"]}); - is(c.name[0], "Bar", "Same name"); - next(); - }, - function() { - ok(true, "mozContact.init without parameters"); - var c = new mozContact({name: ["Foo"]}); - c.init(); - next(); - }, - function() { - ok(true, "mozContact.init resets properties"); - var c = new mozContact({jobTitle: ["Software Engineer"]}); - c.init({nickname: ["Jobless Johnny"]}); - is(c.nickname[0], "Jobless Johnny", "Same nickname"); - ok(!c.jobTitle, "jobTitle is not set"); - next(); - }, - function() { - ok(true, "mozContacts.remove with an ID works"); - var c = new mozContact({name: ["Ephemeral Jimmy"]}); - req = navigator.mozContacts.save(c); - req.onsuccess = function() { - req = navigator.mozContacts.remove(c.id); - req.onsuccess = function() { - req = navigator.mozContacts.find({ - filterBy: ["id"], - filterOp: "equals", - filterValue: c.id - }); - req.onsuccess = function() { - is(req.result.length, 0, "Successfully removed contact by ID"); - next(); - }; - req.onerror = onFailure; - }; - req.onerror = onFailure; - }; - req.onerror = onFailure; - }, - function () { - ok(true, "Adding a new contact"); - createResult1 = new mozContact(properties3); - req = mozContacts.save(createResult1) - req.onsuccess = function () { - ok(createResult1.id, "The contact now has an ID."); - sample_id1 = createResult1.id; - next(); - } - req.onerror = onFailure; - }, - function () { - ok(true, "Adding a new contact2"); - createResult2 = new mozContact(properties4); - req = mozContacts.save(createResult2); - req.onsuccess = function () { - ok(createResult2.id, "The contact now has an ID."); - sample_id2 = createResult2.id; - next(); - }; - req.onerror = onFailure; - }, - function () { - ok(true, "Retrieving all contacts"); - req = mozContacts.find({sortBy: "phoneticFamilyName"}); - req.onsuccess = function () { - is(req.result.length, 2, "Found exactly 2 contact."); - checkContacts(req.result[1], properties3); - next(); - } - req.onerror = onFailure; - }, - function () { - ok(true, "Searching contacts by query1"); - var options = {filterBy: ["phoneticGivenName", "email"], - filterOp: "startsWith", - filterValue: properties3.phoneticGivenName[0].substring(0, 3)} - req = mozContacts.find(options) - req.onsuccess = function () { - is(req.result.length, 1, "Found exactly 1 contact."); - findResult1 = req.result[0]; - ok(findResult1.id == sample_id1, "Same ID"); - checkContacts(findResult1, createResult1); - next(); - } - req.onerror = onFailure; - }, - function () { - ok(true, "Searching contacts by query2"); - var options = {filterBy: ["phoneticGivenName", "email"], - filterOp: "startsWith", - filterValue: properties4.phoneticGivenName[0].substring(0, 3)}; - req = mozContacts.find(options); - req.onsuccess = function () { - is(req.result.length, 1, "Found exactly 1 contact."); - findResult1 = req.result[0]; - is(findResult1.adr.length, 2, "Adr length 2"); - checkContacts(findResult1, createResult2); - next(); - } - req.onerror = onFailure; - }, - clearDatabase, - function () { - ok(true, "Adding 20 contacts"); - for (var i=0; i<19; i++) { - createResult1 = new mozContact(properties3); - req = mozContacts.save(createResult1); - req.onsuccess = function () { - ok(createResult1.id, "The contact now has an ID."); - }; - req.onerror = onFailure; - }; - createResult1 = new mozContact(properties3); - req = mozContacts.save(createResult1); - req.onsuccess = function () { - ok(createResult1.id, "The contact now has an ID."); - checkStrArray(createResult1.name, properties3.name, "Same Name"); - checkCount(20, "20 contacts in DB", next); - }; - req.onerror = onFailure; - }, - function () { - ok(true, "Retrieving all contacts"); - req = mozContacts.find(defaultOptions); - req.onsuccess = function () { - is(req.result.length, 20, "20 Entries."); - next(); - } - req.onerror = onFailure; - }, - function () { - ok(true, "Retrieving all contacts2"); - var options = {filterBy: ["phoneticGivenName"], - filterOp: "startsWith", - filterValue: properties3.phoneticGivenName[0].substring(0, 3)}; - req = mozContacts.find(options); - req.onsuccess = function () { - is(req.result.length, 20, "20 Entries."); - checkContacts(createResult1, req.result[19]); - next(); - } - req.onerror = onFailure; - }, - function () { - ok(true, "Retrieving all contacts3"); - var options = {filterBy: ["phoneticGivenName", "tel", "email"], - filterOp: "startsWith", - filterValue: properties3.phoneticGivenName[0].substring(0, 3)}; - req = mozContacts.find(options); - req.onsuccess = function () { - is(req.result.length, 20, "20 Entries."); - checkContacts(createResult1, req.result[10]); - next(); - } - req.onerror = onFailure; - }, - clearDatabase, - function () { - ok(true, "Testing clone contact"); - createResult1 = new mozContact(properties3); - req = mozContacts.save(createResult1); - req.onsuccess = function () { - ok(createResult1.id, "The contact now has an ID."); - checkStrArray(createResult1.phoneticFamilyName, properties3.phoneticFamilyName, "Same phoneticFamilyName"); - checkStrArray(createResult1.phoneticGivenName, properties3.phoneticGivenName, "Same phoneticGivenName"); - next(); - } - req.onerror = onFailure; - }, - function () { - ok(true, "Retrieving all contacts"); - req = mozContacts.find({sortBy: "phoneticGivenName"}); - req.onsuccess = function () { - is(req.result.length, 1, "1 Entries."); - next(); - } - req.onerror = onFailure; - }, - clearDatabase, - function () { - ok(true, "Test sorting"); - createResult1 = new mozContact(c11); - req = navigator.mozContacts.save(createResult1); - req.onsuccess = function () { - ok(createResult1.id, "The contact now has an ID."); - checkContacts(c11, createResult1); - next(); - }; - req.onerror = onFailure; - }, - function () { - ok(true, "Test sorting"); - createResult1 = new mozContact(c10); - req = navigator.mozContacts.save(createResult1); - req.onsuccess = function () { - ok(createResult1.id, "The contact now has an ID."); - checkContacts(c10, createResult1); - next(); - }; - req.onerror = onFailure; - }, - function () { - ok(true, "Test sorting"); - createResult1 = new mozContact(c12); - req = navigator.mozContacts.save(createResult1); - req.onsuccess = function () { - ok(createResult1.id, "The contact now has an ID."); - checkContacts(c12, createResult1); - next(); - }; - req.onerror = onFailure; - }, - function () { - ok(true, "Test sorting"); - createResult1 = new mozContact(c9); - req = navigator.mozContacts.save(createResult1); - req.onsuccess = function () { - ok(createResult1.id, "The contact now has an ID."); - checkContacts(c9, createResult1); - next(); - }; - req.onerror = onFailure; - }, - function () { - ok(true, "Test sorting"); - var options = {sortBy: "phoneticFamilyName", - sortOrder: "ascending"}; - req = navigator.mozContacts.find(options); - req.onsuccess = function () { - is(req.result.length, 4, "4 results"); - checkContacts(req.result[0], c9); - checkContacts(req.result[1], c10); - checkContacts(req.result[2], c11); - checkContacts(req.result[3], c12); - next(); - }; - req.onerror = onFailure; - }, - function () { - ok(true, "Test sorting"); - var options = {sortBy: "phoneticFamilyName", - sortOrder: "descending"}; - req = navigator.mozContacts.find(options); - req.onsuccess = function () { - is(req.result.length, 4, "4 results"); - checkContacts(req.result[0], c12); - checkContacts(req.result[1], c11); - checkContacts(req.result[2], c10); - checkContacts(req.result[3], c9); - next(); - }; - req.onerror = onFailure; - }, - function () { - ok(true, "Test sorting"); - createResult1 = new mozContact(c13); - req = navigator.mozContacts.save(createResult1); - req.onsuccess = function () { - ok(createResult1.id, "The contact now has an ID."); - checkContacts(c13, createResult1); - next(); - }; - req.onerror = onFailure; - }, - function () { - ok(true, "Test sorting with empty string"); - var options = {sortBy: "phoneticFamilyName", - sortOrder: "ascending"}; - req = navigator.mozContacts.find(options); - req.onsuccess = function () { - is(req.result.length, 5, "5 results"); - checkContacts(req.result[0], c13); - checkContacts(req.result[1], c9); - checkContacts(req.result[2], c10); - checkContacts(req.result[3], c11); - checkContacts(req.result[4], c12); - next(); - }; - req.onerror = onFailure; - }, - clearDatabase, - function () { - ok(true, "Test sorting"); - createResult1 = new mozContact(c15); - req = navigator.mozContacts.save(createResult1); - req.onsuccess = function () { - ok(createResult1.id, "The contact now has an ID."); - checkContacts(c15, createResult1); - next(); - }; - req.onerror = onFailure; - }, - function () { - ok(true, "Test sorting"); - createResult1 = new mozContact(c14); - req = navigator.mozContacts.save(createResult1); - req.onsuccess = function () { - ok(createResult1.id, "The contact now has an ID."); - checkContacts(c14, createResult1); - next(); - }; - req.onerror = onFailure; - }, - function () { - ok(true, "Test sorting"); - createResult1 = new mozContact(c16); - req = navigator.mozContacts.save(createResult1); - req.onsuccess = function () { - ok(createResult1.id, "The contact now has an ID."); - checkContacts(c16, createResult1); - next(); - }; - req.onerror = onFailure; - }, - function () { - // Android does not support published/updated fields. Skip this. - if (isAndroid) { - next(); - return; - } - - ok(true, "Test sorting with published"); - var options = {sortBy: "phoneticFamilyName", - sortOrder: "descending"}; - req = navigator.mozContacts.find(options); - req.onsuccess = function () { - is(req.result.length, 3, "3 results"); - ok(req.result[0].published < req.result[1].published, "Right sorting order"); - ok(req.result[1].published < req.result[2].published, "Right sorting order"); - next(); - }; - req.onerror = onFailure; - }, - clearDatabase, - function () { - ok(true, "all done!\n"); - SimpleTest.finish(); - } -]; - -function next() { - ok(true, "Begin!"); - if (index >= steps.length) { - ok(false, "Shouldn't get here!"); - return; - } - try { - var i = index++; - steps[i](); - } catch(ex) { - ok(false, "Caught exception", ex); - } +function run_tests() { + var iframe = document.querySelector("iframe"); + iframe.src = "file_contacts_basics2.html"; } -start_tests(); +SimpleTest.waitForExplicitFinish(); +onload = function() { + SpecialPowers.pushPermissions([ + {type: "contacts-read", allow: true, context: document}, + {type: "contacts-write", allow: true, context: document}, + {type: "contacts-create", allow: true, context: document}, + ], run_tests); +}; + </script> </pre> </body> </html>
--- a/dom/contacts/tests/test_contacts_blobs.html +++ b/dom/contacts/tests/test_contacts_blobs.html @@ -1,222 +1,29 @@ -<!DOCTYPE html> +<!DOCTYPE HTML> <html> -<!-- -https://bugzilla.mozilla.org/show_bug.cgi?id=674720 ---> <head> - <title>Test for Bug 674720 WebContacts</title> - <script type="text/javascript" src="/MochiKit/MochiKit.js"></script> - <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script> - <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> + <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=674720">Mozilla Bug 674720</a> -<p id="display"></p> -<div id="content" style="display: none"> - -</div> +<iframe></iframe> <pre id="test"> -<script type="text/javascript;version=1.8" src="http://mochi.test:8888/tests/dom/contacts/tests/shared.js"></script> -<script class="testbody" type="text/javascript"> -"use strict"; - -var utils = SpecialPowers.getDOMWindowUtils(window); +<script type="application/javascript"> -function getView(size) -{ - var buffer = new ArrayBuffer(size); - var view = new Uint8Array(buffer); - is(buffer.byteLength, size, "Correct byte length"); - return view; +function run_tests() { + var iframe = document.querySelector("iframe"); + iframe.src = "file_contacts_blobs.html"; } -function getRandomView(size) -{ - var view = getView(size); - for (var i = 0; i < size; i++) { - view[i] = parseInt(Math.random() * 255) - } - return view; -} - -function getRandomBlob(size) -{ - return new Blob([getRandomView(size)], { type: "binary/random" }); -} - -function compareBuffers(buffer1, buffer2) -{ - if (buffer1.byteLength != buffer2.byteLength) { - return false; - } - var view1 = new Uint8Array(buffer1); - var view2 = new Uint8Array(buffer2); - for (var i = 0; i < buffer1.byteLength; i++) { - if (view1[i] != view2[i]) { - return false; - } - } - return true; -} - -function verifyBuffers(buffer1, buffer2, isLast) -{ - ok(compareBuffers(buffer1, buffer2), "Correct blob data"); - if (isLast) - next(); -} - -var randomBlob = getRandomBlob(1024); -var randomBlob2 = getRandomBlob(1024); - -var properties1 = { - name: ["xTestname1"], - givenName: ["xTestname1"], - photo: [randomBlob] -}; - -var properties2 = { - name: ["yTestname2"], - givenName: ["yTestname2"], - photo: [randomBlob, randomBlob2] +SimpleTest.waitForExplicitFinish(); +onload = function() { + SpecialPowers.pushPermissions([ + {type: "contacts-read", allow: true, context: document}, + {type: "contacts-write", allow: true, context: document}, + {type: "contacts-create", allow: true, context: document}, + ], run_tests); }; -var sample_id1; -var createResult1; -var findResult1; - -function verifyBlob(blob1, blob2, isLast) -{ - is(blob1 instanceof Blob, true, - "blob1 is an instance of DOMBlob"); - is(blob2 instanceof Blob, true, - "blob2 is an instance of DOMBlob"); - isnot(blob1 instanceof File, true, - "blob1 is an instance of File"); - isnot(blob2 instanceof File, true, - "blob2 is an instance of File"); - is(blob1.size, blob2.size, "Same size"); - is(blob1.type, blob2.type, "Same type"); - - var buffer1; - var buffer2; - - var reader1 = new FileReader(); - reader1.readAsArrayBuffer(blob2); - reader1.onload = function(event) { - buffer2 = event.target.result; - if (buffer1) { - verifyBuffers(buffer1, buffer2, isLast); - } - } - - var reader2 = new FileReader(); - reader2.readAsArrayBuffer(blob1); - reader2.onload = function(event) { - buffer1 = event.target.result; - if (buffer2) { - verifyBuffers(buffer1, buffer2, isLast); - } - } -} - -function verifyBlobArray(blobs1, blobs2) -{ - is(blobs1 instanceof Array, true, "blobs1 is an array object"); - is(blobs2 instanceof Array, true, "blobs2 is an array object"); - is(blobs1.length, blobs2.length, "Same length"); - - if (!blobs1.length) { - next(); - return; - } - - for (var i = 0; i < blobs1.length; i++) { - verifyBlob(blobs1[i], blobs2[i], i == blobs1.length - 1); - } -} - -var req; - -var steps = [ - function () { - ok(true, "Deleting database"); - req = mozContacts.clear(); - req.onsuccess = function () { - ok(true, "Deleted the database"); - next(); - }; - req.onerror = onFailure; - }, - function () { - ok(true, "Adding contact with photo"); - createResult1 = new mozContact(properties1); - req = navigator.mozContacts.save(createResult1); - req.onsuccess = function () { - ok(createResult1.id, "The contact now has an ID."); - sample_id1 = createResult1.id; - next(); - }; - req.onerror = onFailure; - }, - function () { - ok(true, "Retrieving by substring"); - var options = {filterBy: ["givenName"], - filterOp: "startsWith", - filterValue: properties1.givenName[0].substring(0,3)}; - req = mozContacts.find(options); - req.onsuccess = function () { - ok(req.result.length == 1, "Found exactly 1 contact."); - findResult1 = req.result[0]; - ok(findResult1.id == sample_id1, "Same ID"); - verifyBlobArray(findResult1.photo, properties1.photo); - }; - req.onerror = onFailure; - }, - function () { - ok(true, "Adding contact with 2 photos"); - createResult1 = new mozContact(properties2); - req = navigator.mozContacts.save(createResult1); - req.onsuccess = function () { - ok(createResult1.id, "The contact now has an ID."); - sample_id1 = createResult1.id; - next(); - }; - req.onerror = onFailure; - }, - function () { - ok(true, "Retrieving by substring"); - var options = {filterBy: ["givenName"], - filterOp: "startsWith", - filterValue: properties2.givenName[0].substring(0,3)}; - req = mozContacts.find(options); - req.onsuccess = function () { - ok(req.result.length == 1, "Found exactly 1 contact."); - findResult1 = req.result[0]; - ok(findResult1.id == sample_id1, "Same ID"); - verifyBlobArray(findResult1.photo, properties2.photo); - }; - req.onerror = onFailure; - }, - function () { - ok(true, "Deleting database"); - req = mozContacts.clear() - req.onsuccess = function () { - ok(true, "Deleted the database"); - next(); - } - req.onerror = onFailure; - }, - function () { - ok(true, "all done!\n"); - - SimpleTest.finish(); - } -]; - -start_tests(); </script> </pre> </body> </html>
--- a/dom/contacts/tests/test_contacts_events.html +++ b/dom/contacts/tests/test_contacts_events.html @@ -1,41 +1,29 @@ <!DOCTYPE HTML> <html> -<!-- -https://bugzilla.mozilla.org/show_bug.cgi?id=764667 ---> <head> - <title>Test for Bug 678695</title> <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script> <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> </head> <body> -<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=764667">Mozilla Bug 764667</a> -<p id="display"></p> -<div id="content" style="display: none"> - -</div> +<iframe></iframe> <pre id="test"> <script type="application/javascript"> -/** Test for Bug 764667 **/ - -SpecialPowers.addPermission("contacts-read", true, document); - -var e = new MozContactChangeEvent("contactchanged", {contactID: "123", reason: "create"}); -ok(e, "Should have contactsChange event!"); -is(e.contactID, "123", "ID should be 123."); -is(e.reason, "create", "Reason should be create."); +function run_tests() { + var iframe = document.querySelector("iframe"); + iframe.src = "file_contacts_events.html"; +} -e = new MozContactChangeEvent("contactchanged", {contactID: "test", reason: "test"}); -is(e.contactID, "test", "Name should be 'test'."); -is(e.reason, "test", "Name should be 'test'."); - -e = new MozContactChangeEvent("contactchanged", {contactID: "a", reason: ""}); -is(e.contactID, "a", "Name should be a."); -is(e.reason, "", "Value should be empty"); - +SimpleTest.waitForExplicitFinish(); +onload = function() { + SpecialPowers.pushPermissions([ + {type: "contacts-read", allow: true, context: document}, + {type: "contacts-write", allow: true, context: document}, + {type: "contacts-create", allow: true, context: document}, + ], run_tests); +}; </script> </pre> </body> -</html> \ No newline at end of file +</html>
--- a/dom/contacts/tests/test_contacts_getall.html +++ b/dom/contacts/tests/test_contacts_getall.html @@ -1,152 +1,29 @@ -<!DOCTYPE html> +<!DOCTYPE HTML> <html> -<!-- -https://bugzilla.mozilla.org/show_bug.cgi?id=836519 ---> <head> - <title>Mozilla Bug 836519</title> - <script type="text/javascript" src="/MochiKit/MochiKit.js"></script> - <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script> - <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> + <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=836519">Mozilla Bug 836519</a> -<p id="display"></p> -<div id="content" style="display: none"> - -</div> +<iframe></iframe> <pre id="test"> -<script type="text/javascript;version=1.8" src="http://mochi.test:8888/tests/dom/contacts/tests/shared.js"></script> -<script class="testbody" type="text/javascript;version=1.8"> -"use strict"; - -let req; - -let steps = [ - function start() { - SpecialPowers.Cc["@mozilla.org/tools/profiler;1"].getService(SpecialPowers.Ci.nsIProfiler).AddMarker("GETALL_START"); - next(); - }, - clearDatabase, - addContacts, +<script type="application/javascript"> - function() { - ok(true, "Delete the current contact while iterating"); - req = mozContacts.getAll({}); - let count = 0; - let previousId = null; - req.onsuccess = function() { - if (req.result) { - ok(true, "on success"); - if (previousId) { - isnot(previousId, req.result.id, "different contacts returned"); - } - previousId = req.result.id; - count++; - let delReq = mozContacts.remove(req.result); - delReq.onsuccess = function() { - ok(true, "deleted current contact"); - req.continue(); - }; - } else { - is(count, 40, "returned 40 contacts"); - next(); - } - }; - }, - - clearDatabase, - addContacts, +function run_tests() { + var iframe = document.querySelector("iframe"); + iframe.src = "file_contacts_getall.html"; +} - function() { - ok(true, "Iterating through the contact list inside a cursor callback"); - let count1 = 0, count2 = 0; - let req1 = mozContacts.getAll({}); - let req2; - req1.onsuccess = function() { - if (count1 == 0) { - count1++; - req2 = mozContacts.getAll({}); - req2.onsuccess = function() { - if (req2.result) { - count2++; - req2.continue(); - } else { - is(count2, 40, "inner cursor returned 40 contacts"); - req1.continue(); - } - }; - } else { - if (req1.result) { - count1++; - req1.continue(); - } else { - is(count1, 40, "outer cursor returned 40 contacts"); - next(); - } - } - }; - }, - - clearDatabase, - addContacts, +SimpleTest.waitForExplicitFinish(); +onload = function() { + SpecialPowers.pushPermissions([ + {type: "contacts-read", allow: true, context: document}, + {type: "contacts-write", allow: true, context: document}, + {type: "contacts-create", allow: true, context: document}, + ], run_tests); +}; - function() { - ok(true, "20 concurrent cursors"); - const NUM_CURSORS = 20; - let completed = 0; - for (let i = 0; i < NUM_CURSORS; ++i) { - mozContacts.getAll({}).onsuccess = (function(i) { - let count = 0; - return function(event) { - let req = event.target; - if (req.result) { - count++; - req.continue(); - } else { - is(count, 40, "cursor " + i + " returned 40 contacts"); - if (++completed == NUM_CURSORS) { - next(); - } - } - }; - })(i); - } - }, - - clearDatabase, - addContacts, - - function() { - if (!SpecialPowers.isMainProcess()) { - // We stop calling continue() intentionally here to see if the cursor gets - // cleaned up properly in the parent. - ok(true, "Leaking a cursor"); - req = mozContacts.getAll({ - sortBy: "familyName", - sortOrder: "ascending" - }); - req.onsuccess = function(event) { - next(); - }; - req.onerror = onFailure; - } else { - next(); - } - }, - - clearDatabase, - - function() { - ok(true, "all done!\n"); - SpecialPowers.Cc["@mozilla.org/tools/profiler;1"].getService(SpecialPowers.Ci.nsIProfiler).AddMarker("GETALL_END"); - SimpleTest.finish(); - } -]; - -start_tests(); </script> </pre> </body> </html>
--- a/dom/contacts/tests/test_contacts_getall2.html +++ b/dom/contacts/tests/test_contacts_getall2.html @@ -1,120 +1,29 @@ -<!DOCTYPE html> +<!DOCTYPE HTML> <html> -<!-- -https://bugzilla.mozilla.org/show_bug.cgi?id=836519 ---> <head> - <title>Mozilla Bug 836519</title> - <script type="text/javascript" src="/MochiKit/MochiKit.js"></script> - <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script> - <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> + <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=836519">Mozilla Bug 836519</a> -<p id="display"></p> -<div id="content" style="display: none"> - -</div> +<iframe></iframe> <pre id="test"> -<script type="text/javascript;version=1.8" src="http://mochi.test:8888/tests/dom/contacts/tests/shared.js"></script> -<script class="testbody" type="text/javascript;version=1.8"> -"use strict"; -let req; +<script type="application/javascript"> -let steps = [ - clearDatabase, - function() { - // add a contact - createResult1 = new mozContact({}); - req = navigator.mozContacts.save(createResult1); - req.onsuccess = function() { - next(); - }; - req.onerror = onFailure; - }, - - getOne(), - getOne("Retrieving one contact with getAll - cached"), - - clearDatabase, - addContacts, - - getAll(), - getAll("Retrieving 40 contacts with getAll - cached"), +function run_tests() { + var iframe = document.querySelector("iframe"); + iframe.src = "file_contacts_getall2.html"; +} - function() { - ok(true, "Deleting one contact"); - req = mozContacts.remove(createResult1); - req.onsuccess = function() { - next(); - }; - req.onerror = onFailure; - }, - function() { - ok(true, "Test cache invalidation"); - req = mozContacts.getAll({}); - let count = 0; - req.onsuccess = function(event) { - ok(true, "on success"); - if (req.result) { - ok(true, "result is valid"); - count++; - req.continue(); - } else { - is(count, 39, "last contact - 39 contacts returned"); - next(); - } - }; - req.onerror = onFailure; - }, - - clearDatabase, - addContacts, +SimpleTest.waitForExplicitFinish(); +onload = function() { + SpecialPowers.pushPermissions([ + {type: "contacts-read", allow: true, context: document}, + {type: "contacts-write", allow: true, context: document}, + {type: "contacts-create", allow: true, context: document}, + ], run_tests); +}; - function() { - ok(true, "Test cache consistency when deleting contact during getAll"); - req = mozContacts.find({}); - req.onsuccess = function(e) { - let lastContact = e.target.result[e.target.result.length-1]; - req = mozContacts.getAll({}); - let count = 0; - let firstResult = true; - req.onsuccess = function(event) { - ok(true, "on success"); - if (firstResult) { - if (req.result) { - count++; - } - let delReq = mozContacts.remove(lastContact); - delReq.onsuccess = function() { - firstResult = false; - req.continue(); - }; - } else { - if (req.result) { - ok(true, "result is valid"); - count++; - req.continue(); - } else { - is(count, 40, "last contact - 40 contacts returned"); - next(); - } - } - }; - }; - }, - - clearDatabase, - - function() { - ok(true, "all done!\n"); - SimpleTest.finish(); - } -]; - -start_tests(); </script> </pre> </body> </html>
--- a/dom/contacts/tests/test_contacts_international.html +++ b/dom/contacts/tests/test_contacts_international.html @@ -1,274 +1,29 @@ -<!DOCTYPE html> +<!DOCTYPE HTML> <html> -<!-- -https://bugzilla.mozilla.org/show_bug.cgi?id=815833 ---> <head> - <title>Test for Bug 815833 WebContacts</title> - <script type="text/javascript" src="/MochiKit/MochiKit.js"></script> - <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script> - <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> + <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=815833">Mozilla Bug 815833</a> -<p id="display"></p> -<div id="content" style="display: none"> - -</div> +<iframe></iframe> <pre id="test"> -<script type="text/javascript;version=1.8" src="http://mochi.test:8888/tests/dom/contacts/tests/shared.js"></script> -<script class="testbody" type="text/javascript"> -"use strict"; - -var number1 = { - local: "7932012345", - international: "+557932012345" -}; +<script type="application/javascript"> -var number2 = { - local: "7932012346", - international: "+557932012346" -}; - -var properties1 = { - name: ["Testname1"], - tel: [{type: ["work"], value: number1.local, carrier: "testCarrier"} , {type: ["home", "fax"], value: number2.local}], -}; +function run_tests() { + var iframe = document.querySelector("iframe"); + iframe.src = "file_contacts_international.html"; +} -var shortNumber = "888"; -var properties2 = { - name: ["Testname2"], - tel: [{type: ["work"], value: shortNumber, carrier: "testCarrier"}] -}; - -var number3 = { - local: "7932012345", - international: "+557932012345" -}; - -var properties3 = { - name: ["Testname2"], - tel: [{value: number3.international}] +SimpleTest.waitForExplicitFinish(); +onload = function() { + SpecialPowers.pushPermissions([ + {type: "contacts-read", allow: true, context: document}, + {type: "contacts-write", allow: true, context: document}, + {type: "contacts-create", allow: true, context: document}, + ], run_tests); }; -var req; -var createResult1; -var findResult1; -var sample_id1; - -var steps = [ - function () { - ok(true, "Deleting database"); - req = mozContacts.clear(); - req.onsuccess = function () { - ok(true, "Deleted the database"); - next(); - }; - req.onerror = onFailure; - }, - function () { - ok(true, "Adding a new contact1"); - createResult1 = new mozContact(properties1); - req = navigator.mozContacts.save(createResult1); - req.onsuccess = function () { - ok(createResult1.id, "The contact now has an ID."); - sample_id1 = createResult1.id; - next(); - }; - req.onerror = onFailure; - }, - function () { - ok(true, "Adding a new contact2"); - var createResult2 = new mozContact(properties2); - req = navigator.mozContacts.save(createResult2); - req.onsuccess = function () { - ok(createResult2.id, "The contact now has an ID."); - next(); - }; - req.onerror = onFailure; - }, - function () { - ok(true, "Searching for local number"); - var options = {filterBy: ["tel"], - filterOp: "startsWith", - filterValue: number1.local}; - req = mozContacts.find(options); - req.onsuccess = function () { - is(req.result.length, 1, "Found exactly 1 contact."); - findResult1 = req.result[0]; - is(findResult1.id, sample_id1, "Same ID"); - next(); - }; - req.onerror = onFailure; - }, - function () { - ok(true, "Searching for international number"); - var options = {filterBy: ["tel"], - filterOp: "startsWith", - filterValue: number1.international}; - req = mozContacts.find(options); - req.onsuccess = function () { - is(req.result.length, 0, "Found exactly 0 contacts."); - next(); - }; - req.onerror = onFailure; - }, - function () { - ok(true, "Searching for a short number matching the prefix"); - var shortNumber = number1.local.substring(0, 3); - var options = {filterBy: ["tel"], - filterOp: "equals", - filterValue: shortNumber}; - req = mozContacts.find(options); - req.onsuccess = function() { - is(req.result.length, 0, "The prefix short number should not match any contact."); - next(); - }; - req.onerror = onFailure; - }, - function () { - ok(true, "Searching for a short number matching the suffix"); - var shortNumber = number1.local.substring(number1.local.length - 3); - var options = {filterBy: ["tel"], - filterOp: "equals", - filterValue: shortNumber}; - req = mozContacts.find(options); - req.onsuccess = function() { - is(req.result.length, 0, "The suffix short number should not match any contact."); - next(); - }; - req.onerror = onFailure; - }, - function () { - ok(true, "Searching for a short number matching a contact"); - var options = {filterBy: ["tel"], - filterOp: "equals", - filterValue: shortNumber}; - req = mozContacts.find(options); - req.onsuccess = function() { - is(req.result.length, 1, "Found the contact equally matching the shortNumber."); - next(); - }; - req.onerror = onFailure; - }, - function() { - ok(true, "Modifying number"); - if (!findResult1) { - SpecialPowers.executeSoon(next); - } else { - findResult1.tel[0].value = number2.local; - req = mozContacts.save(findResult1); - req.onsuccess = function () { - next(); - }; - } - }, - function () { - ok(true, "Searching for local number"); - var options = {filterBy: ["tel"], - filterOp: "startsWith", - filterValue: number1.local}; - req = mozContacts.find(options); - req.onsuccess = function () { - is(req.result.length, 0, "Found exactly 0 contact."); - next(); - }; - req.onerror = onFailure; - }, - function () { - ok(true, "Searching for local number"); - var options = {filterBy: ["tel"], - filterOp: "startsWith", - filterValue: number1.international}; - req = mozContacts.find(options); - req.onsuccess = function () { - is(req.result.length, 0, "Found exactly 0 contact."); - next(); - }; - req.onerror = onFailure; - }, - function () { - ok(true, "Searching for local number"); - var options = {filterBy: ["tel"], - filterOp: "startsWith", - filterValue: number2.local}; - req = mozContacts.find(options); - req.onsuccess = function () { - is(req.result.length, 1, "Found exactly 1 contact."); - findResult1 = req.result[0]; - is(findResult1.id, sample_id1, "Same ID"); - next(); - }; - req.onerror = onFailure; - }, - function () { - ok(true, "Searching for local number"); - var options = {filterBy: ["tel"], - filterOp: "startsWith", - filterValue: number2.international}; - req = mozContacts.find(options); - req.onsuccess = function () { - is(req.result.length, 0, "Found exactly 1 contact."); - next(); - }; - req.onerror = onFailure; - }, - function () { - ok(true, "Deleting database"); - req = mozContacts.clear(); - req.onsuccess = function () { - ok(true, "Deleted the database"); - next(); - } - req.onerror = onFailure; - }, - function () { - ok(true, "Adding a contact with a Brazilian country code"); - createResult1 = new mozContact(properties3); - req = navigator.mozContacts.save(createResult1); - req.onsuccess = function () { - ok(createResult1.id, "The contact now has an ID."); - sample_id1 = createResult1.id; - next(); - }; - req.onerror = onFailure; - }, - function () { - ok(true, "Searching for Brazilian number using local number"); - var options = {filterBy: ["tel"], - filterOp: "match", - filterValue: number3.local}; - req = mozContacts.find(options); - req.onsuccess = function () { - is(req.result.length, 1, "Found exactly 1 contact."); - findResult1 = req.result[0]; - is(findResult1.id, sample_id1, "Same ID"); - next(); - }; - req.onerror = onFailure; - }, - function () { - ok(true, "Deleting database"); - req = mozContacts.clear(); - req.onsuccess = function () { - ok(true, "Deleted the database"); - next(); - } - req.onerror = onFailure; - }, - function () { - ok(true, "all done!\n"); - SimpleTest.finish(); - } -]; - -SpecialPowers.pushPrefEnv({ - set: [ - ["ril.lastKnownSimMcc", "000"] - ] -}, start_tests); </script> </pre> </body> </html>
--- a/dom/contacts/tests/test_contacts_substringmatching.html +++ b/dom/contacts/tests/test_contacts_substringmatching.html @@ -1,348 +1,29 @@ -<!DOCTYPE html> +<!DOCTYPE HTML> <html> -<!-- -https://bugzilla.mozilla.org/show_bug.cgi?id=877302 ---> <head> - <title>Test for Bug 877302 substring matching for WebContacts</title> - <script type="text/javascript" src="/MochiKit/MochiKit.js"></script> - <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script> - <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> + <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=877302">Mozilla Bug 877302</a> -<p id="display"></p> -<div id="content" style="display: none"> - -</div> +<iframe></iframe> <pre id="test"> -<script type="text/javascript;version=1.8" src="http://mochi.test:8888/tests/dom/contacts/tests/shared.js"></script> -<script class="testbody" type="text/javascript"> -"use strict"; - -var substringLength = 8; - -var prop = { - tel: [{value: "7932012345" }, {value: "7932012346"}] -}; +<script type="application/javascript"> -var prop2 = { - tel: [{value: "01187654321" }] -}; - -var prop3 = { - tel: [{ value: "+43332112346" }] -}; +function run_tests() { + var iframe = document.querySelector("iframe"); + iframe.src = "file_contacts_substringmatching.html"; +} -var prop4 = { - tel: [{ value: "(0414) 233-9888" }] -}; - -var brazilianNumber = { - international1: "0041557932012345", - international2: "+557932012345" -}; - -var prop5 = { - tel: [{value: brazilianNumber.international2}] +SimpleTest.waitForExplicitFinish(); +onload = function() { + SpecialPowers.pushPermissions([ + {type: "contacts-read", allow: true, context: document}, + {type: "contacts-write", allow: true, context: document}, + {type: "contacts-create", allow: true, context: document}, + ], run_tests); }; -var req; -var steps = [ - function () { - ok(true, "Deleting database"); - req = mozContacts.clear() - req.onsuccess = function () { - ok(true, "Deleted the database"); - next(); - } - req.onerror = onFailure; - }, - function () { - ok(true, "Adding contact"); - createResult1 = new mozContact(prop); - req = navigator.mozContacts.save(createResult1); - req.onsuccess = function () { - ok(createResult1.id, "The contact now has an ID."); - sample_id1 = createResult1.id; - next(); - }; - req.onerror = onFailure; - }, - function () { - ok(true, "Retrieving all contacts"); - req = mozContacts.find({}); - req.onsuccess = function () { - is(req.result.length, 1, "One contact."); - findResult1 = req.result[0]; - next(); - }; - req.onerror = onFailure; - }, - function () { - ok(true, "Retrieving by substring 1"); - var length = prop.tel[0].value.length; - var num = prop.tel[0].value.substring(length - substringLength, length); - var options = {filterBy: ["tel"], - filterOp: "match", - filterValue: num}; - req = mozContacts.find(options); - req.onsuccess = function () { - is(req.result.length, 1, "Found exactly 1 contact."); - findResult1 = req.result[0]; - ok(findResult1.id == sample_id1, "Same ID"); - is(findResult1.tel[0].value, "7932012345", "Same Value"); - next(); - }; - req.onerror = onFailure; - }, - function () { - ok(true, "Retrieving by substring 2"); - var length = prop.tel[1].value.length; - var num = prop.tel[1].value.substring(length - substringLength, length); - var options = {filterBy: ["tel"], - filterOp: "match", - filterValue: num}; - req = mozContacts.find(options); - req.onsuccess = function () { - is(req.result.length, 1, "Found exactly 1 contact."); - findResult1 = req.result[0]; - ok(findResult1.id == sample_id1, "Same ID"); - is(findResult1.tel[0].value, "7932012345", "Same Value"); - next(); - }; - req.onerror = onFailure; - }, - function () { - ok(true, "Retrieving by substring 3"); - var length = prop.tel[0].value.length; - var num = prop.tel[0].value.substring(length - substringLength + 1, length); - var options = {filterBy: ["tel"], - filterOp: "match", - filterValue: num}; - req = mozContacts.find(options); - req.onsuccess = function () { - is(req.result.length, 0, "Found exactly 0 contacts."); - next(); - }; - req.onerror = onFailure; - }, - function () { - ok(true, "Retrieving by substring 4"); - var length = prop.tel[0].value.length; - var num = prop.tel[0].value.substring(length - substringLength - 1, length); - var options = {filterBy: ["tel"], - filterOp: "match", - filterValue: num}; - req = mozContacts.find(options); - req.onsuccess = function () { - is(req.result.length, 1, "Found exactly 1 contacts."); - next(); - }; - req.onerror = onFailure; - }, - function () { - ok(true, "Adding contact"); - createResult1 = new mozContact(prop2); - req = navigator.mozContacts.save(createResult1); - req.onsuccess = function () { - ok(createResult1.id, "The contact now has an ID."); - sample_id1 = createResult1.id; - next(); - }; - req.onerror = onFailure; - }, - function () { - ok(true, "Retrieving by substring 5"); - var options = {filterBy: ["tel"], - filterOp: "match", - filterValue: "87654321"}; - req = mozContacts.find(options); - req.onsuccess = function () { - is(req.result.length, 1, "Found exactly 1 contacts."); - next(); - }; - req.onerror = onFailure; - }, - function () { - ok(true, "Retrieving by substring 6"); - var options = {filterBy: ["tel"], - filterOp: "match", - filterValue: "01187654321"}; - req = mozContacts.find(options); - req.onsuccess = function () { - is(req.result.length, 1, "Found exactly 1 contacts."); - next(); - }; - req.onerror = onFailure; - }, - function () { - ok(true, "Retrieving by substring 7"); - var options = {filterBy: ["tel"], - filterOp: "match", - filterValue: "909087654321"}; - req = mozContacts.find(options); - req.onsuccess = function () { - is(req.result.length, 1, "Found exactly 1 contacts."); - next(); - }; - req.onerror = onFailure; - }, - function () { - ok(true, "Retrieving by substring 8"); - var options = {filterBy: ["tel"], - filterOp: "match", - filterValue: "0411187654321"}; - req = mozContacts.find(options); - req.onsuccess = function () { - is(req.result.length, 1, "Found exactly 1 contacts."); - next(); - }; - req.onerror = onFailure; - }, - function () { - ok(true, "Retrieving by substring 9"); - var options = {filterBy: ["tel"], - filterOp: "match", - filterValue: "90411187654321"}; - req = mozContacts.find(options); - req.onsuccess = function () { - is(req.result.length, 1, "Found exactly 1 contacts."); - next(); - }; - req.onerror = onFailure; - }, - function () { - ok(true, "Retrieving by substring 10"); - var options = {filterBy: ["tel"], - filterOp: "match", - filterValue: "+551187654321"}; - req = mozContacts.find(options); - req.onsuccess = function () { - is(req.result.length, 1, "Found exactly 1 contacts."); - next(); - }; - req.onerror = onFailure; - }, - function () { - ok(true, "Deleting database"); - req = mozContacts.clear() - req.onsuccess = function () { - ok(true, "Deleted the database"); - next(); - } - req.onerror = onFailure; - }, - function () { - ok(true, "Adding contact"); - createResult1 = new mozContact(prop3); - req = navigator.mozContacts.save(createResult1); - req.onsuccess = function () { - ok(createResult1.id, "The contact now has an ID."); - sample_id1 = createResult1.id; - next(); - }; - req.onerror = onFailure; - }, - function () { - if (!isAndroid) { // Bug 905927 - ok(true, "Retrieving by substring 1"); - var length = prop3.tel[0].value.length; - var num = prop3.tel[0].value.substring(length - substringLength, length); - var options = {filterBy: ["tel"], - filterOp: "match", - filterValue: num}; - req = mozContacts.find(options); - req.onsuccess = function () { - is(req.result.length, 0, "Found exactly 0 contacts."); - next(); - }; - req.onerror = onFailure; - } else { - SpecialPowers.executeSoon(next); - } - }, - function () { - ok(true, "Adding contact"); - createResult1 = new mozContact(prop4); - req = navigator.mozContacts.save(createResult1); - req.onsuccess = function () { - ok(createResult1.id, "The contact now has an ID."); - sample_id1 = createResult1.id; - next(); - }; - req.onerror = onFailure; - }, - function () { - ok(true, "Retrieving by substring 1"); - var num = "(0424) 233-9888" - var options = {filterBy: ["tel"], - filterOp: "match", - filterValue: num}; - req = mozContacts.find(options); - req.onsuccess = function () { - is(req.result.length, 1, "Found exactly 1 contacts."); - next(); - }; - req.onerror = onFailure; - }, - function () { - ok(true, "Deleting database"); - req = mozContacts.clear() - req.onsuccess = function () { - ok(true, "Deleted the database"); - next(); - } - req.onerror = onFailure; - }, - function () { - ok(true, "Adding a new contact with a Brazilian country code"); - createResult1 = new mozContact(prop5); - req = navigator.mozContacts.save(createResult1); - req.onsuccess = function () { - ok(createResult1.id, "The contact now has an ID."); - sample_id1 = createResult1.id; - next(); - }; - req.onerror = onFailure; - }, - function () { - ok(true, "Searching for international number with prefix"); - var options = {filterBy: ["tel"], - filterOp: "match", - filterValue: brazilianNumber.international1}; - req = mozContacts.find(options); - req.onsuccess = function () { - ok(req.result.length == 1, "Found exactly 1 contact."); - findResult1 = req.result[0]; - ok(findResult1.id == sample_id1, "Same ID"); - next(); - }; - req.onerror = onFailure; - }, - function () { - ok(true, "Deleting database"); - req = mozContacts.clear() - req.onsuccess = function () { - ok(true, "Deleted the database"); - next(); - } - req.onerror = onFailure; - }, - function () { - ok(true, "all done!\n"); - SimpleTest.finish(); - } -]; - -SpecialPowers.pushPrefEnv({ - set: [ - ["dom.phonenumber.substringmatching.BR", substringLength], - ["ril.lastKnownSimMcc", "724"] - ] -}, start_tests); </script> </pre> </body> </html>
--- a/dom/contacts/tests/test_contacts_substringmatchingCL.html +++ b/dom/contacts/tests/test_contacts_substringmatchingCL.html @@ -1,204 +1,29 @@ -<!DOCTYPE html> +<!DOCTYPE HTML> <html> -<!-- -https://bugzilla.mozilla.org/show_bug.cgi?id=877302 ---> <head> - <title>Test for Bug 949537 substring matching for WebContacts</title> - <script type="text/javascript" src="/MochiKit/MochiKit.js"></script> - <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script> - <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> + <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=949537">Mozilla Bug 949537</a> -<p id="display"></p> -<div id="content" style="display: none"> - -</div> +<iframe></iframe> <pre id="test"> -<script type="text/javascript;version=1.8" src="http://mochi.test:8888/tests/dom/contacts/tests/shared.js"></script> -<script class="testbody" type="text/javascript"> -"use strict"; +<script type="application/javascript"> -var landlineNumber = "+56 2 27654321"; +function run_tests() { + var iframe = document.querySelector("iframe"); + iframe.src = "file_contacts_substringmatchingCL.html"; +} -var number = { - local: "87654321", - international: "+56 9 87654321" -}; - -var properties = { - name: ["Testname2"], - tel: [{value: number.international}] +SimpleTest.waitForExplicitFinish(); +onload = function() { + SpecialPowers.pushPermissions([ + {type: "contacts-read", allow: true, context: document}, + {type: "contacts-write", allow: true, context: document}, + {type: "contacts-create", allow: true, context: document}, + ], run_tests); }; -var req; -var steps = [ - function () { - ok(true, "Adding a contact with a Chilean number"); - createResult1 = new mozContact(properties); - req = navigator.mozContacts.save(createResult1); - req.onsuccess = function () { - ok(createResult1.id, "The contact now has an ID."); - sample_id1 = createResult1.id; - next(); - }; - req.onerror = onFailure; - }, - function () { - ok(true, "Searching for Chilean number with prefix"); - req = mozContacts.find({ - filterBy: ["tel"], - filterOp: "match", - filterValue: number.international - }); - req.onsuccess = function () { - is(req.result.length, 1, "Found exactly 1 contact."); - findResult1 = req.result[0]; - is(findResult1.id, sample_id1, "Same ID"); - next(); - }; - req.onerror = onFailure; - }, - function () { - ok(true, "Searching for Chilean number using local number"); - req = mozContacts.find({ - filterBy: ["tel"], - filterOp: "match", - filterValue: number.local - }); - req.onsuccess = function () { - is(req.result.length, 1, "Found 0 contacts."); - next(); - }; - req.onerror = onFailure; - }, - - clearDatabase, - - function () { - ok(true, "Adding contact with mobile number"); - createResult1 = new mozContact({tel: [{value: number.international}]}); - req = navigator.mozContacts.save(createResult1); - req.onsuccess = function () { - ok(createResult1.id, "The contact now has an ID."); - sample_id1 = createResult1.id; - next(); - }; - req.onerror = onFailure; - }, - function () { - ok(true, "Retrieving all contacts"); - req = mozContacts.find({}); - req.onsuccess = function () { - is(req.result.length, 1, "One contact."); - findResult1 = req.result[0]; - next(); - }; - req.onerror = onFailure; - }, - function () { - ok(true, "Retrieving by last 8 digits"); - req = mozContacts.find({ - filterBy: ["tel"], - filterOp: "match", - filterValue: number.international.slice(-8) - }); - req.onsuccess = function () { - is(req.result.length, 1, "Found exactly 1 contact."); - findResult1 = req.result[0]; - is(findResult1.id, sample_id1, "Same ID"); - is(findResult1.tel[0].value, number.international, "Same Value"); - next(); - }; - req.onerror = onFailure; - }, - function () { - ok(true, "Retrieving by last 9 digits"); - req = mozContacts.find({ - filterBy: ["tel"], - filterOp: "match", - filterValue: number.international.slice(-9) - }); - req.onsuccess = function () { - is(req.result.length, 1, "Found exactly 1 contact."); - findResult1 = req.result[0]; - is(findResult1.id, sample_id1, "Same ID"); - is(findResult1.tel[0].value, number.international, "Same Value"); - next(); - }; - req.onerror = onFailure; - }, - function () { - ok(true, "Retrieving by last 6 digits"); - req = mozContacts.find({ - filterBy: ["tel"], - filterOp: "match", - filterValue: number.international.slice(-6) - }); - req.onsuccess = function () { - is(req.result.length, 0, "Found exactly zero contacts."); - next(); - }; - req.onerror = onFailure; - }, - - clearDatabase, - - function () { - ok(true, "Adding contact with landline number"); - createResult1 = new mozContact({tel: [{value: landlineNumber}]}); - req = navigator.mozContacts.save(createResult1); - req.onsuccess = function () { - ok(createResult1.id, "The contact now has an ID."); - sample_id1 = createResult1.id; - next(); - }; - req.onerror = onFailure; - }, - function () { - ok(true, "Retrieving all contacts"); - req = mozContacts.find({}); - req.onsuccess = function () { - is(req.result.length, 1, "One contact."); - findResult1 = req.result[0]; - next(); - }; - req.onerror = onFailure; - }, - function () { - ok(true, "Retrieving by last 7 digits (local number) with landline calling prefix"); - req = mozContacts.find({ - filterBy: ["tel"], - filterOp: "match", - filterValue: "022" + landlineNumber.slice(-7) - }); - req.onsuccess = function () { - is(req.result.length, 1, "Found exactly 1 contact."); - findResult1 = req.result[0]; - is(findResult1.id, sample_id1, "Same ID"); - is(findResult1.tel[0].value, landlineNumber, "Same Value"); - next(); - }; - req.onerror = onFailure; - }, - - clearDatabase, - - function () { - ok(true, "all done!\n"); - SimpleTest.finish(); - } -]; - -SpecialPowers.pushPrefEnv({ - set: [ - ["dom.phonenumber.substringmatching.CL", 8], - ["ril.lastKnownSimMcc", "730"] - ] -}, start_tests); </script> </pre> </body> </html>
--- a/dom/contacts/tests/test_contacts_substringmatchingVE.html +++ b/dom/contacts/tests/test_contacts_substringmatchingVE.html @@ -1,132 +1,29 @@ -<!DOCTYPE html> +<!DOCTYPE HTML> <html> -<!-- -https://bugzilla.mozilla.org/show_bug.cgi?id=877302 ---> <head> - <title>Test for Bug 877302 substring matching for WebContacts</title> - <script type="text/javascript" src="/MochiKit/MochiKit.js"></script> - <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script> - <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> + <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=877302">Mozilla Bug 877302</a> -<p id="display"></p> -<div id="content" style="display: none"> - -</div> +<iframe></iframe> <pre id="test"> -<script type="text/javascript;version=1.8" src="http://mochi.test:8888/tests/dom/contacts/tests/shared.js"></script> -<script class="testbody" type="text/javascript"> -"use strict"; +<script type="application/javascript"> + +function run_tests() { + var iframe = document.querySelector("iframe"); + iframe.src = "file_contacts_substringmatchingVE.html"; +} -var prop = { - tel: [{value: "7932012345" }, {value: "7704143727591"}] -}; - -var prop2 = { - tel: [{value: "7932012345" }, {value: "+58 212 5551212"}] +SimpleTest.waitForExplicitFinish(); +onload = function() { + SpecialPowers.pushPermissions([ + {type: "contacts-read", allow: true, context: document}, + {type: "contacts-write", allow: true, context: document}, + {type: "contacts-create", allow: true, context: document}, + ], run_tests); }; -var req; -var steps = [ - function () { - ok(true, "Deleting database"); - req = mozContacts.clear() - req.onsuccess = function () { - ok(true, "Deleted the database"); - next(); - } - req.onerror = onFailure; - }, - function () { - ok(true, "Adding contact"); - createResult1 = new mozContact(prop); - req = navigator.mozContacts.save(createResult1); - req.onsuccess = function () { - ok(createResult1.id, "The contact now has an ID."); - sample_id1 = createResult1.id; - next(); - }; - req.onerror = onFailure; - }, - function () { - ok(true, "Retrieving all contacts"); - req = mozContacts.find({}); - req.onsuccess = function () { - is(req.result.length, 1, "One contact."); - findResult1 = req.result[0]; - next(); - }; - req.onerror = onFailure; - }, - function () { - ok(true, "Retrieving by substring 1"); - var length = prop.tel[0].value.length; - var num = "04143727591" - var options = {filterBy: ["tel"], - filterOp: "match", - filterValue: num}; - req = mozContacts.find(options); - req.onsuccess = function () { - is(req.result.length, 1, "Found exactly 1 contact."); - findResult1 = req.result[0]; - ok(findResult1.id == sample_id1, "Same ID"); - is(findResult1.tel[1].value, "7704143727591", "Same Value"); - next(); - }; - req.onerror = onFailure; - }, - function () { - ok(true, "Adding contact"); - createResult1 = new mozContact(prop2); - req = navigator.mozContacts.save(createResult1); - req.onsuccess = function () { - ok(createResult1.id, "The contact now has an ID."); - sample_id1 = createResult1.id; - next(); - }; - req.onerror = onFailure; - }, - function () { - ok(true, "Retrieving by substring 2"); - var num = "5551212"; - var options = {filterBy: ["tel"], - filterOp: "match", - filterValue: num}; - req = mozContacts.find(options); - req.onsuccess = function () { - is(req.result.length, 1, "Found exactly 1 contact."); - findResult1 = req.result[0]; - ok(findResult1.id == sample_id1, "Same ID"); - is(findResult1.tel[1].value, "+58 212 5551212", "Same Value"); - next(); - }; - req.onerror = onFailure; - }, - function () { - ok(true, "Deleting database"); - req = mozContacts.clear() - req.onsuccess = function () { - ok(true, "Deleted the database"); - next(); - } - req.onerror = onFailure; - }, - function () { - ok(true, "all done!\n"); - SimpleTest.finish(); - } -]; - -SpecialPowers.pushPrefEnv({ - set: [ - ["dom.phonenumber.substringmatching.VE", 7], - ["ril.lastKnownSimMcc", "734"] - ] -}, start_tests); </script> </pre> </body> </html>
--- a/dom/contacts/tests/test_migration.html +++ b/dom/contacts/tests/test_migration.html @@ -1,194 +1,29 @@ -<!DOCTYPE html> +<!DOCTYPE HTML> <html> <head> - <title>Migration tests</title> - <script type="text/javascript" src="/MochiKit/MochiKit.js"></script> - <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script> - <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> + <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> </head> <body> -<h1>migration tests</h1> -<p id="display"></p> -<div id="content" style="display: none"> - -</div> +<iframe></iframe> <pre id="test"> -<script type="text/javascript;version=1.8" src="shared.js"></script> -<script class="testbody" type="text/javascript"> -"use strict"; - -var backend, contactsCount, allContacts; -function loadChromeScript() { - var url = SimpleTest.getTestFileURL("test_migration_chrome.js"); - backend = SpecialPowers.loadChromeScript(url); -} +<script type="application/javascript"> -function addBackendEvents() { - backend.addMessageListener("createDB.success", function(count) { - contactsCount = count; - ok(true, "Created the database"); - next(); - }); - backend.addMessageListener("createDB.error", function(err) { - ok(false, err); - next(); - }); - - backend.addMessageListener("deleteDB.success", function() { - ok(true, "Deleted the database"); - next(); - }); - backend.addMessageListener("deleteDB.error", function(err) { - ok(false, err); - next(); - }); -} - -function createDB(version) { - info("Will create the DB at version " + version); - backend.sendAsyncMessage("createDB", version); -} - -function deleteDB() { - info("Will delete the DB."); - backend.sendAsyncMessage("deleteDB"); +function run_tests() { + var iframe = document.querySelector("iframe"); + iframe.src = "file_migration.html"; } -var steps = [ - function setupChromeScript() { - loadChromeScript(); - addBackendEvents(); - next(); - }, - - deleteDB, // let's be sure the DB does not exist yet - createDB.bind(null, 12), - - function testAccessMozContacts() { - info("Checking we have the right number of contacts: " + contactsCount); - var req = mozContacts.getCount(); - req.onsuccess = function onsuccess() { - ok(true, "Could access the mozContacts API"); - is(this.result, contactsCount, "Contacts count is correct"); - next(); - }; - - req.onerror = function onerror() { - ok(false, "Couldn't access the mozContacts API"); - next(); - }; - }, - - function testRetrieveAllContacts() { - /* if the migration does not work right, either we'll have an error, or the - contacts won't be migrated properly and thus will fail WebIDL conversion, - which will manifest as a timeout */ - info("Checking the contacts are corrected to obey WebIDL constraints. (upgrades 14 to 17)"); - var req = mozContacts.find(); - req.onsuccess = function onsuccess() { - if (this.result) { - is(this.result.length, contactsCount, "Contacts array length is correct"); - allContacts = this.result; - next(); - } else { - ok(false, "Could access the mozContacts API but got no contacts!"); - next(); - } - }; - - req.onerror = function onerror() { - ok(false, "Couldn't access the mozContacts API"); - next(); - }; - }, - - function checkNameIndex() { - info("Checking name index migration (upgrades 17 to 19)."); - if (!allContacts) { - next(); - } - - var count = allContacts.length; - - function finishRequest() { - count--; - if (!count) { - next(); - } - } +SimpleTest.waitForExplicitFinish(); +onload = function() { + SpecialPowers.pushPermissions([ + {type: "contacts-read", allow: true, context: document}, + {type: "contacts-write", allow: true, context: document}, + {type: "contacts-create", allow: true, context: document}, + ], run_tests); +}; - allContacts.forEach(function(contact) { - var name = contact.name && contact.name[0]; - if (!name) { - count--; - return; - } - - var req = mozContacts.find({ - filterBy: ["name"], - filterValue: name, - filterOp: "equals" - }); - - req.onsuccess = function onsuccess() { - if (this.result) { - info("Found contact '" + name + "', checking it's the correct one."); - checkContacts(this.result[0], contact); - } else { - ok(false, "Could not find contact with name '" + name + "'"); - } - - finishRequest(); - }; - - req.onerror = function onerror() { - ok(false, "Error while finding contact with name '" + name + "'!"); - finishRequest(); - } - }); - - if (!count) { - ok(false, "No contact had a name, this is unexpected."); - next(); - } - }, - - function checkSubstringMatching() { - var subject = "0004567890"; // the last 7 digits are the same that at least one contact - info("Looking for a contact matching " + subject); - var req = mozContacts.find({ - filterValue: subject, - filterOp: "match", - filterBy: ["tel"], - filterLimit: 1 - }); - - req.onsuccess = function onsuccess() { - if (this.result && this.result[0]) { - ok(true, "Found a contact with number " + this.result[0].tel[0].value); - } - next(); - }; - - req.onerror = function onerror() { - ok(false, "Error while finding contact for substring matching check!"); - next(); - }; - }, - - deleteDB, - - function finish() { - backend.destroy(); - info("all done!\n"); - SimpleTest.finish(); - } -]; - -// this is the Mcc for Brazil, so that we trigger the previous pref -SpecialPowers.pushPrefEnv({"set": [["dom.phonenumber.substringmatching.BR", 7], - ["ril.lastKnownSimMcc", "724"]]}, start_tests); </script> </pre> </body> </html>
--- a/dom/contacts/tests/test_permission_denied.html +++ b/dom/contacts/tests/test_permission_denied.html @@ -1,120 +1,29 @@ -<!DOCTYPE html> +<!DOCTYPE HTML> <html> -<!-- -https://bugzilla.mozilla.org/show_bug.cgi?id=1081873 ---> <head> - <title>Test for Bug 1081873</title> - <script type="text/javascript" src="/MochiKit/MochiKit.js"></script> - <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script> - <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> + <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=1081873">Mozilla Bug 1081873</a> -<p id="display"></p> -<div id="content" style="display: none"> - -</div> +<iframe></iframe> <pre id="test"> -<script class="testbody" type="text/javascript"> - -"use strict"; - -SpecialPowers.addPermission("contacts-write", false, document); -SpecialPowers.addPermission("contacts-read", false, document); -SpecialPowers.addPermission("contacts-create", false, document); - -function onUnexpectedSuccess() { - ok(false, "Unexpected success"); - next(); -} +<script type="application/javascript"> -function onExpectedError(event) { - is(event.target.error.name, PERMISSION_DENIED, "Expected PERMISSION_DENIED"); - next(); -} - -const PERMISSION_DENIED = "PERMISSION_DENIED"; - -var index = 0; - -function next() { - info("Step " + index); - if (index >= steps.length) { - ok(false, "Shouldn't get here!"); - return; - } - try { - var i = index++; - steps[i](); - } catch(ex) { - ok(false, "Caught exception", ex); - } +function run_tests() { + var iframe = document.querySelector("iframe"); + iframe.src = "file_permission_denied.html"; } -var steps = [ - function() { - ok(true, "Add contact without permission"); - var req = navigator.mozContacts.save(new mozContact({})); - req.onsuccess = onUnexpectedSuccess; - req.onerror = onExpectedError; - }, - function() { - ok(true, "Find contact without permission"); - var req = navigator.mozContacts.find({}); - req.onsuccess = onUnexpectedSuccess; - req.onerror = onExpectedError; - }, - function() { - ok(true, "Get all contacts without permission"); - var req = navigator.mozContacts.getAll(); - req.onsuccess = onUnexpectedSuccess; - req.onerror = onExpectedError; - }, - function() { - ok(true, "Remove contact without permission"); - var req = navigator.mozContacts.remove("aId"); - req.onsuccess = onUnexpectedSuccess; - req.onerror = onExpectedError; - }, - function() { - ok(true, "Clear contacts without permission"); - var req = navigator.mozContacts.clear(); - req.onsuccess = onUnexpectedSuccess; - req.onerror = onExpectedError; - }, - function() { - ok(true, "Get revision without permission"); - var req = navigator.mozContacts.getRevision(); - req.onsuccess = onUnexpectedSuccess; - req.onerror = onExpectedError; - }, - function() { - ok(true, "Get count without permission"); - var req = navigator.mozContacts.getCount(); - req.onsuccess = onUnexpectedSuccess; - req.onerror = function() { - is(req.error.name, PERMISSION_DENIED, "Expected PERMISSION_DENIED"); - SimpleTest.finish(); - }; - } -]; - SimpleTest.waitForExplicitFinish(); - -const DENY = SpecialPowers.Ci.nsIPermissionManager.DENY_ACTION; -var interval = setInterval(function() { - if (!SpecialPowers.testPermission("contacts-read", DENY, document) || - !SpecialPowers.testPermission("contacts-write", DENY, document) || - !SpecialPowers.testPermission("contacts-create", DENY, document)) { - return; - } - clearInterval(interval); - next(); -}, 1000); +onload = function() { + SpecialPowers.pushPermissions([ + {type: "contacts-read", allow: false, context: document}, + {type: "contacts-write", allow: false, context: document}, + {type: "contacts-create", allow: false, context: document}, + ], run_tests); +}; </script> </pre> </body> </html>
--- a/dom/html/HTMLMediaElement.cpp +++ b/dom/html/HTMLMediaElement.cpp @@ -2798,16 +2798,18 @@ nsresult HTMLMediaElement::InitializeDec return NS_ERROR_FAILURE; RefPtr<MediaDecoder> decoder = aOriginal->Clone(this); if (!decoder) return NS_ERROR_FAILURE; LOG(LogLevel::Debug, ("%p Cloned decoder %p from %p", this, decoder.get(), aOriginal)); decoder->SetMediaSeekable(aOriginal->IsMediaSeekable()); + decoder->SetMediaSeekableOnlyInBufferedRanges( + aOriginal->IsMediaSeekableOnlyInBufferedRanges()); RefPtr<MediaResource> resource = originalResource->CloneData(decoder->GetResourceCallback()); if (!resource) { LOG(LogLevel::Debug, ("%p Failed to cloned stream for decoder %p", this, decoder.get())); return NS_ERROR_FAILURE; }
--- a/dom/icc/tests/marionette/test_icc_contact_read.js +++ b/dom/icc/tests/marionette/test_icc_contact_read.js @@ -1,13 +1,14 @@ /* Any copyright is dedicated to the Public Domain. * http://creativecommons.org/publicdomain/zero/1.0/ */ MARIONETTE_TIMEOUT = 60000; MARIONETTE_HEAD_JS = "head.js"; +MARIONETTE_CONTEXT = "chrome"; function testReadContacts(aIcc, aType) { log("testReadContacts: type=" + aType); let iccId = aIcc.iccInfo.iccid; return aIcc.readContacts(aType) .then((aResult) => { is(Array.isArray(aResult), true);
--- a/dom/ipc/ContentChild.cpp +++ b/dom/ipc/ContentChild.cpp @@ -142,16 +142,17 @@ #include "nsVolume.h" #include "nsVolumeService.h" #include "SpeakerManagerService.h" #endif #ifdef XP_WIN #include <process.h> #define getpid _getpid +#include "mozilla/widget/AudioSession.h" #endif #ifdef MOZ_X11 #include "mozilla/X11Util.h" #endif #ifdef ACCESSIBILITY #include "nsIAccessibilityService.h" @@ -3038,16 +3039,20 @@ ContentChild::RecvShutdown() } nsCOMPtr<nsIObserverService> os = services::GetObserverService(); if (os) { os->NotifyObservers(static_cast<nsIContentChild*>(this), "content-child-shutdown", nullptr); } +#if defined(XP_WIN) + mozilla::widget::StopAudioSession(); +#endif + GetIPCChannel()->SetAbortOnError(false); #ifdef MOZ_ENABLE_PROFILER_SPS if (profiler_is_active()) { // We're shutting down while we were profiling. Send the // profile up to the parent so that we don't lose this // information. Unused << RecvGatherProfile(); @@ -3156,16 +3161,36 @@ ContentChild::RecvGamepadUpdate(const Ga RefPtr<GamepadService> svc(GamepadService::GetService()); if (svc) { svc->Update(aGamepadEvent); } #endif return true; } +bool +ContentChild::RecvSetAudioSessionData(const nsID& aId, + const nsString& aDisplayName, + const nsString& aIconPath) +{ +#if defined(XP_WIN) + if (NS_FAILED(mozilla::widget::RecvAudioSessionData(aId, aDisplayName, + aIconPath))) { + return true; + } + + // Ignore failures here; we can't really do anything about them + mozilla::widget::StartAudioSession(); + return true; +#else + NS_RUNTIMEABORT("Not Reached!"); + return false; +#endif +} + // This code goes here rather than nsGlobalWindow.cpp because nsGlobalWindow.cpp // can't include ContentChild.h since it includes windows.h. static uint64_t gNextWindowID = 0; // We use only 53 bits for the window ID so that it can be converted to and from // a JS value without loss of precision. The upper bits of the window ID hold the // process ID. The lower bits identify the window.
--- a/dom/ipc/ContentChild.h +++ b/dom/ipc/ContentChild.h @@ -605,16 +605,22 @@ public: AllocPContentPermissionRequestChild(const InfallibleTArray<PermissionRequest>& aRequests, const IPC::Principal& aPrincipal, const TabId& aTabId) override; virtual bool DeallocPContentPermissionRequestChild(PContentPermissionRequestChild* actor) override; virtual bool RecvGamepadUpdate(const GamepadChangeEvent& aGamepadEvent) override; + // Windows specific - set up audio session + virtual bool + RecvSetAudioSessionData(const nsID& aId, + const nsString& aDisplayName, + const nsString& aIconPath) override; + private: virtual void ActorDestroy(ActorDestroyReason why) override; virtual void ProcessingError(Result aCode, const char* aReason) override; /** * Exit *now*. Do not shut down XPCOM, do not pass Go, do not run * static destructors, do not collect $200.
--- a/dom/ipc/ContentParent.cpp +++ b/dom/ipc/ContentParent.cpp @@ -258,16 +258,20 @@ using namespace mozilla::system; #include "nsIProfiler.h" #include "nsIProfileSaveEvent.h" #endif #ifdef MOZ_GAMEPAD #include "mozilla/dom/GamepadMonitoring.h" #endif +#ifdef XP_WIN +#include "mozilla/widget/AudioSession.h" +#endif + #include "VRManagerParent.h" // for VRManagerParent static NS_DEFINE_CID(kCClipboardCID, NS_CLIPBOARD_CID); #if defined(XP_WIN) // e10s forced enable pref, defined in nsAppRunner.cpp extern const char* kForceEnableE10sPref; #endif @@ -2615,16 +2619,26 @@ ContentParent::InitInternal(ProcessPrior MOZ_ASSERT(static_cast<const FileDescriptor&>(brokerFd).IsValid()); } } #endif if (shouldSandbox && !SendSetProcessSandbox(brokerFd)) { KillHard("SandboxInitFailed"); } #endif +#if defined(XP_WIN) + // Send the info needed to join the browser process's audio session. + nsID id; + nsString sessionName; + nsString iconPath; + if (NS_SUCCEEDED(mozilla::widget::GetAudioSessionData(id, sessionName, + iconPath))) { + Unused << SendSetAudioSessionData(id, sessionName, iconPath); + } +#endif } bool ContentParent::IsAlive() const { return mIsAlive; }
--- a/dom/ipc/PContent.ipdl +++ b/dom/ipc/PContent.ipdl @@ -737,16 +737,23 @@ child: */ async PushWithData(nsCString scope, Principal principal, uint8_t[] data); /** * Send a `pushsubscriptionchange` event to a service worker in the child. */ async PushSubscriptionChange(nsCString scope, Principal principal); + /** + * Windows specific: associate this content process with the browsers + * audio session. + */ + async SetAudioSessionData(nsID aID, + nsString aDisplayName, + nsString aIconPath); parent: /** * Tell the content process some attributes of itself. This is * among the first information queried by content processes after * startup. (The message is sync to allow the content process to * control when it receives the information.) * * |id| is a unique ID among all subprocesses. When |isForApp &&
--- a/dom/media/MediaDataDemuxer.h +++ b/dom/media/MediaDataDemuxer.h @@ -65,16 +65,20 @@ public: // The actual Track ID is to be retrieved by calling // MediaTrackDemuxer::TrackInfo. virtual already_AddRefed<MediaTrackDemuxer> GetTrackDemuxer(TrackInfo::TrackType aType, uint32_t aTrackNumber) = 0; // Returns true if the underlying resource allows seeking. virtual bool IsSeekable() const = 0; + // Returns true if the underlying resource can only seek within buffered + // ranges. + virtual bool IsSeekableOnlyInBufferedRanges() const { return false; } + // Returns the media's crypto information, or nullptr if media isn't // encrypted. virtual UniquePtr<EncryptionInfo> GetCrypto() { return nullptr; } // Notifies the demuxer that the underlying resource has received more data
--- a/dom/media/MediaDecoder.cpp +++ b/dom/media/MediaDecoder.cpp @@ -559,16 +559,18 @@ MediaDecoder::MediaDecoder(MediaDecoderO , mPlaybackBytesPerSecond(AbstractThread::MainThread(), 0.0, "MediaDecoder::mPlaybackBytesPerSecond (Canonical)") , mPlaybackRateReliable(AbstractThread::MainThread(), true, "MediaDecoder::mPlaybackRateReliable (Canonical)") , mDecoderPosition(AbstractThread::MainThread(), 0, "MediaDecoder::mDecoderPosition (Canonical)") , mMediaSeekable(AbstractThread::MainThread(), true, "MediaDecoder::mMediaSeekable (Canonical)") + , mMediaSeekableOnlyInBufferedRanges(AbstractThread::MainThread(), false, + "MediaDecoder::mMediaSeekableOnlyInBufferedRanges (Canonical)") , mTelemetryReported(false) { MOZ_COUNT_CTOR(MediaDecoder); MOZ_ASSERT(NS_IsMainThread()); MediaMemoryTracker::AddMediaDecoder(this); mAudioChannel = AudioChannelService::GetDefaultAudioChannel(); mResourceCallback->Connect(this); @@ -870,16 +872,17 @@ MediaDecoder::MetadataLoaded(nsAutoPtr<M MOZ_ASSERT(NS_IsMainThread()); MOZ_ASSERT(!mShuttingDown); DECODER_LOG("MetadataLoaded, channels=%u rate=%u hasAudio=%d hasVideo=%d", aInfo->mAudio.mChannels, aInfo->mAudio.mRate, aInfo->HasAudio(), aInfo->HasVideo()); SetMediaSeekable(aInfo->mMediaSeekable); + SetMediaSeekableOnlyInBufferedRanges(aInfo->mMediaSeekableOnlyInBufferedRanges); mInfo = aInfo.forget(); ConstructMediaTracks(); // Make sure the element and the frame (if any) are told about // our new size. if (aEventVisibility != MediaDecoderEventVisibility::Suppressed) { mFiredMetadataLoaded = true; mOwner->MetadataLoaded(mInfo, nsAutoPtr<const MetadataTags>(aTags.forget())); @@ -1372,39 +1375,54 @@ MediaDecoder::UpdateEstimatedMediaDurati } void MediaDecoder::SetMediaSeekable(bool aMediaSeekable) { MOZ_ASSERT(NS_IsMainThread()); mMediaSeekable = aMediaSeekable; } +void +MediaDecoder::SetMediaSeekableOnlyInBufferedRanges(bool aMediaSeekableOnlyInBufferedRanges){ + MOZ_ASSERT(NS_IsMainThread()); + mMediaSeekableOnlyInBufferedRanges = aMediaSeekableOnlyInBufferedRanges; +} + bool MediaDecoder::IsTransportSeekable() { MOZ_ASSERT(NS_IsMainThread()); return GetResource()->IsTransportSeekable(); } bool MediaDecoder::IsMediaSeekable() { MOZ_ASSERT(NS_IsMainThread()); NS_ENSURE_TRUE(GetStateMachine(), false); return mMediaSeekable; } +bool +MediaDecoder::IsMediaSeekableOnlyInBufferedRanges() +{ + MOZ_ASSERT(NS_IsMainThread()); + return mMediaSeekableOnlyInBufferedRanges; +} + media::TimeIntervals MediaDecoder::GetSeekable() { MOZ_ASSERT(NS_IsMainThread()); // We can seek in buffered range if the media is seekable. Also, we can seek // in unbuffered ranges if the transport level is seekable (local file or the - // server supports range requests, etc.) - if (!IsMediaSeekable()) { + // server supports range requests, etc.) or in cue-less WebMs + if (IsMediaSeekableOnlyInBufferedRanges()) { + return GetBuffered(); + } else if (!IsMediaSeekable()) { return media::TimeIntervals(); } else if (!IsTransportSeekable()) { return GetBuffered(); } else { return media::TimeIntervals( media::TimeInterval(media::TimeUnit::FromMicroseconds(0), IsInfinite() ? media::TimeUnit::FromInfinity() :
--- a/dom/media/MediaDecoder.h +++ b/dom/media/MediaDecoder.h @@ -248,22 +248,27 @@ protected: // changed, this causes a durationchanged event to fire to the media // element. void UpdateEstimatedMediaDuration(int64_t aDuration) override; public: // Called from HTMLMediaElement when owner document activity changes virtual void SetElementVisibility(bool aIsVisible) {} - // Set a flag indicating whether seeking is supported + // Set a flag indicating whether random seeking is supported void SetMediaSeekable(bool aMediaSeekable); + // Set a flag indicating whether seeking is supported only in buffered ranges + void SetMediaSeekableOnlyInBufferedRanges(bool aMediaSeekableOnlyInBufferedRanges); - // Returns true if this media supports seeking. False for example for WebM - // files without an index and chained ogg files. + // Returns true if this media supports random seeking. False for example with + // chained ogg files. bool IsMediaSeekable(); + // Returns true if this media supports seeking only in buffered ranges. True + // for example in WebMs with no cues + bool IsMediaSeekableOnlyInBufferedRanges(); // Returns true if seeking is supported on a transport level (e.g. the server // supports range requests, we are playing a file, etc.). bool IsTransportSeekable(); // Return the time ranges that can be seeked into. virtual media::TimeIntervals GetSeekable(); // Set the end time of the media resource. When playback reaches @@ -787,16 +792,19 @@ protected: // is up to consuming the stream. This is not adjusted during decoder // seek operations, but it's updated at the end when we start playing // back again. Canonical<int64_t> mDecoderPosition; // True if the media is seekable (i.e. supports random access). Canonical<bool> mMediaSeekable; + // True if the media is only seekable within its buffered ranges. + Canonical<bool> mMediaSeekableOnlyInBufferedRanges; + public: AbstractCanonical<media::NullableTimeUnit>* CanonicalDurationOrNull() override; AbstractCanonical<double>* CanonicalVolume() { return &mVolume; } AbstractCanonical<double>* CanonicalPlaybackRate() { return &mPlaybackRate; } @@ -828,16 +836,19 @@ public: return &mPlaybackRateReliable; } AbstractCanonical<int64_t>* CanonicalDecoderPosition() { return &mDecoderPosition; } AbstractCanonical<bool>* CanonicalMediaSeekable() { return &mMediaSeekable; } + AbstractCanonical<bool>* CanonicalMediaSeekableOnlyInBufferedRanges() { + return &mMediaSeekableOnlyInBufferedRanges; + } private: // Notify owner when the audible state changed void NotifyAudibleStateChanged(); /* Functions called by ResourceCallback */ // A media stream is assumed to be infinite if the metadata doesn't
--- a/dom/media/MediaDecoderStateMachine.cpp +++ b/dom/media/MediaDecoderStateMachine.cpp @@ -263,16 +263,18 @@ MediaDecoderStateMachine::MediaDecoderSt mPlaybackBytesPerSecond(mTaskQueue, 0.0, "MediaDecoderStateMachine::mPlaybackBytesPerSecond (Mirror)"), mPlaybackRateReliable(mTaskQueue, true, "MediaDecoderStateMachine::mPlaybackRateReliable (Mirror)"), mDecoderPosition(mTaskQueue, 0, "MediaDecoderStateMachine::mDecoderPosition (Mirror)"), mMediaSeekable(mTaskQueue, true, "MediaDecoderStateMachine::mMediaSeekable (Mirror)"), + mMediaSeekableOnlyInBufferedRanges(mTaskQueue, false, + "MediaDecoderStateMachine::mMediaSeekableOnlyInBufferedRanges (Mirror)"), mDuration(mTaskQueue, NullableTimeUnit(), "MediaDecoderStateMachine::mDuration (Canonical"), mIsShutdown(mTaskQueue, false, "MediaDecoderStateMachine::mIsShutdown (Canonical)"), mNextFrameStatus(mTaskQueue, MediaDecoderOwner::NEXT_FRAME_UNINITIALIZED, "MediaDecoderStateMachine::mNextFrameStatus (Canonical)"), mCurrentPosition(mTaskQueue, 0, "MediaDecoderStateMachine::mCurrentPosition (Canonical)"), @@ -345,16 +347,17 @@ MediaDecoderStateMachine::Initialization mVolume.Connect(aDecoder->CanonicalVolume()); mLogicalPlaybackRate.Connect(aDecoder->CanonicalPlaybackRate()); mPreservesPitch.Connect(aDecoder->CanonicalPreservesPitch()); mSameOriginMedia.Connect(aDecoder->CanonicalSameOriginMedia()); mPlaybackBytesPerSecond.Connect(aDecoder->CanonicalPlaybackBytesPerSecond()); mPlaybackRateReliable.Connect(aDecoder->CanonicalPlaybackRateReliable()); mDecoderPosition.Connect(aDecoder->CanonicalDecoderPosition()); mMediaSeekable.Connect(aDecoder->CanonicalMediaSeekable()); + mMediaSeekableOnlyInBufferedRanges.Connect(aDecoder->CanonicalMediaSeekableOnlyInBufferedRanges()); // Initialize watchers. mWatchManager.Watch(mBuffered, &MediaDecoderStateMachine::BufferedRangeUpdated); mWatchManager.Watch(mState, &MediaDecoderStateMachine::UpdateNextFrameStatus); mWatchManager.Watch(mAudioCompleted, &MediaDecoderStateMachine::UpdateNextFrameStatus); mWatchManager.Watch(mVideoCompleted, &MediaDecoderStateMachine::UpdateNextFrameStatus); mWatchManager.Watch(mVolume, &MediaDecoderStateMachine::VolumeChanged); mWatchManager.Watch(mLogicalPlaybackRate, &MediaDecoderStateMachine::LogicalPlaybackRateChanged); @@ -1469,19 +1472,18 @@ RefPtr<MediaDecoder::SeekPromise> MediaDecoderStateMachine::Seek(SeekTarget aTarget) { MOZ_ASSERT(OnTaskQueue()); if (IsShutdown()) { return MediaDecoder::SeekPromise::CreateAndReject(/* aIgnored = */ true, __func__); } - // We need to be able to seek both at a transport level and at a media level - // to seek. - if (!mMediaSeekable) { + // We need to be able to seek in some way + if (!mMediaSeekable && !mMediaSeekableOnlyInBufferedRanges) { DECODER_WARN("Seek() function should not be called on a non-seekable state machine"); return MediaDecoder::SeekPromise::CreateAndReject(/* aIgnored = */ true, __func__); } MOZ_ASSERT(mState > DECODER_STATE_DECODING_METADATA, "We should have got duration already"); if (mState < DECODER_STATE_DECODING || @@ -2187,16 +2189,17 @@ MediaDecoderStateMachine::FinishShutdown mVolume.DisconnectIfConnected(); mLogicalPlaybackRate.DisconnectIfConnected(); mPreservesPitch.DisconnectIfConnected(); mSameOriginMedia.DisconnectIfConnected(); mPlaybackBytesPerSecond.DisconnectIfConnected(); mPlaybackRateReliable.DisconnectIfConnected(); mDecoderPosition.DisconnectIfConnected(); mMediaSeekable.DisconnectIfConnected(); + mMediaSeekableOnlyInBufferedRanges.DisconnectIfConnected(); mDuration.DisconnectAll(); mIsShutdown.DisconnectAll(); mNextFrameStatus.DisconnectAll(); mCurrentPosition.DisconnectAll(); mPlaybackOffset.DisconnectAll(); mIsAudioDataAudible.DisconnectAll();
--- a/dom/media/MediaDecoderStateMachine.h +++ b/dom/media/MediaDecoderStateMachine.h @@ -1234,16 +1234,19 @@ private: Mirror<bool> mPlaybackRateReliable; // Current decoding position in the stream. Mirror<int64_t> mDecoderPosition; // True if the media is seekable (i.e. supports random access). Mirror<bool> mMediaSeekable; + // True if the media is seekable only in buffered ranges. + Mirror<bool> mMediaSeekableOnlyInBufferedRanges; + // Duration of the media. This is guaranteed to be non-null after we finish // decoding the first frame. Canonical<media::NullableTimeUnit> mDuration; // Whether we're currently in or transitioning to shutdown state. Canonical<bool> mIsShutdown; // The status of our next frame. Mirrored on the main thread and used to
--- a/dom/media/MediaFormatReader.cpp +++ b/dom/media/MediaFormatReader.cpp @@ -332,16 +332,18 @@ MediaFormatReader::OnDemuxerInitDone(nsr int64_t audioDuration = HasAudio() ? mInfo.mAudio.mDuration : 0; int64_t duration = std::max(videoDuration, audioDuration); if (duration != -1) { mInfo.mMetadataDuration = Some(TimeUnit::FromMicroseconds(duration)); } mInfo.mMediaSeekable = mDemuxer->IsSeekable(); + mInfo.mMediaSeekableOnlyInBufferedRanges = + mDemuxer->IsSeekableOnlyInBufferedRanges(); if (!videoActive && !audioActive) { mMetadataPromise.Reject(ReadMetadataFailureReason::METADATA_ERROR, __func__); return; } mInitDone = true; RefPtr<MetadataHolder> metadata = new MetadataHolder(); @@ -1423,17 +1425,17 @@ MediaFormatReader::Seek(SeekTarget aTarg MOZ_DIAGNOSTIC_ASSERT(mSeekPromise.IsEmpty()); MOZ_DIAGNOSTIC_ASSERT(!mVideo.HasPromise()); MOZ_DIAGNOSTIC_ASSERT(!mAudio.HasPromise()); MOZ_DIAGNOSTIC_ASSERT(mPendingSeekTime.isNothing()); MOZ_DIAGNOSTIC_ASSERT(mVideo.mTimeThreshold.isNothing()); MOZ_DIAGNOSTIC_ASSERT(mAudio.mTimeThreshold.isNothing()); - if (!mInfo.mMediaSeekable) { + if (!mInfo.mMediaSeekable && !mInfo.mMediaSeekableOnlyInBufferedRanges) { LOG("Seek() END (Unseekable)"); return SeekPromise::CreateAndReject(NS_ERROR_FAILURE, __func__); } if (mShutdown) { return SeekPromise::CreateAndReject(NS_ERROR_FAILURE, __func__); }
--- a/dom/media/MediaInfo.h +++ b/dom/media/MediaInfo.h @@ -412,16 +412,19 @@ public: // The Ogg reader tries to kinda-sorta compute the duration by seeking to the // end and determining the timestamp of the last frame. This isn't useful as // a duration until we know the start time, so we need to track it separately. media::NullableTimeUnit mUnadjustedMetadataEndTime; // True if the media is seekable (i.e. supports random access). bool mMediaSeekable = true; + // True if the media is only seekable within its buffered ranges. + bool mMediaSeekableOnlyInBufferedRanges = false; + EncryptionInfo mCrypto; }; class SharedTrackInfo { NS_INLINE_DECL_THREADSAFE_REFCOUNTING(SharedTrackInfo) public: SharedTrackInfo(const TrackInfo& aOriginal, uint32_t aStreamID) : mInfo(aOriginal.Clone())
--- a/dom/media/test/manifest.js +++ b/dom/media/test/manifest.js @@ -501,20 +501,26 @@ var gFastSeekTests = [ ]; function IsWindows8OrLater() { var re = /Windows NT (\d.\d)/; var winver = manifestNavigator().userAgent.match(re); return winver && winver.length == 2 && parseFloat(winver[1]) >= 6.2; } +// These files are WebMs without cues. They're seekable within their buffered +// ranges. If work renders WebMs fully seekable these files should be moved +// into gSeekTests +var gCuelessWebMTests = [ + { name:"no-cues.webm", type:"video/webm", duration:3.967 }, +]; + // These are files that are non seekable, due to problems with the media, // for example broken or missing indexes. var gUnseekableTests = [ - { name:"no-cues.webm", type:"video/webm" }, { name:"bogus.duh", type:"bogus/duh"} ]; var androidVersion = -1; // non-Android platforms if (manifestNavigator().userAgent.indexOf("Mobile") != -1 || manifestNavigator().userAgent.indexOf("Tablet") != -1) { // See nsSystemInfo.cpp, the getProperty('version') returns different value // on each platforms, so we need to distinguish the android and B2G platform.
--- a/dom/media/test/mochitest.ini +++ b/dom/media/test/mochitest.ini @@ -618,16 +618,19 @@ skip-if = buildapp == 'b2g' || (toolkit [test_can_play_type_no_ogg.html] [test_can_play_type_ogg.html] [test_chaining.html] [test_clone_media_element.html] skip-if = (toolkit == 'android' && processor == 'x86') #x86 only bug 914439 [test_closing_connections.html] [test_constants.html] [test_controls.html] +[test_cueless_webm_seek-1.html] +[test_cueless_webm_seek-2.html] +[test_cueless_webm_seek-3.html] [test_currentTime.html] [test_decode_error.html] [test_decoder_disable.html] [test_defaultMuted.html] [test_delay_load.html] skip-if = buildapp == 'b2g' && toolkit != 'gonk' # bug 1082984 [test_dormant_playback.html] skip-if = (os == 'win' && os_version == '5.1') || (os != 'win' && toolkit != 'gonk')
new file mode 100644 --- /dev/null +++ b/dom/media/test/test_cueless_webm_seek-1.html @@ -0,0 +1,136 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=657791 +--> +<head> + <title>Test for Bug 657791</title> + <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> + <script type="text/javascript" src="manifest.js"></script> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=657791">Mozilla Bug 657791</a> + +<p id="display"></p> +<div id="content" style="display: none"> + +</div> +<pre id="test"> +<script type="application/javascript"> + +// Subset of seek tests for cueless WebMs. When random seeking (rather than just +// in buffered ranges) is implemented for WebM, these tests can be removed and +// the cueless WebM(s) references can be moved to the general test_seek test +// array. +// Test array is defined in manifest.js + +var manager = new MediaTestManager; + +// Exercise functionality as in test_seek-1 +function testWebM1(e) { + var v = e.target; + v.removeEventListener('loadeddata', testWebM1); + + var startPassed = false; + var endPassed = false; + var seekFlagStart = false; + var seekFlagEnd = false; + var readonly = true; + var completed = false; + + ok(v.buffered.length >= 1, "Should have a buffered range"); + var halfBuffered = v.buffered.end(0) / 2; + + function startTest() { + is(v.seekable.start(0), v.buffered.start(0), "Seekable start should be buffered start"); + is(v.seekable.end(0), v.buffered.end(0), "Seekable end should be buffered end"); + ok(!completed, "Should not be completed yet"); + ok(!v.seeking, "seeking should default to false"); + try { + v.seeking = true; + readonly = v.seeking === false; + } + catch(e) { + readonly = "threw exception: " + e; + } + is(readonly, true, "seeking should be readonly"); + + v.currentTime = halfBuffered; + seekFlagStart = v.seeking; + } + + function seekStarted() { + ok(!completed, "should not be completed yet"); + startPassed = true; + } + + function seekEnded() { + ok(!completed, "should not be completed yet"); + ok(Math.abs(v.currentTime - halfBuffered) < 0.1, + "Video currentTime should be around " + halfBuffered + ": " + v.currentTime + " (seeked)"); + endPassed = true; + seekFlagEnd = v.seeking; + v.play(); + } + + function playbackEnded() { + ok(!completed, "should not be completed yet"); + + completed = true; + ok(startPassed, "seeking event"); + ok(endPassed, "seeked event"); + ok(seekFlagStart, "seeking flag on start should be true"); + ok(!seekFlagEnd, "seeking flag on end should be false"); + removeNodeAndSource(v); + manager.finished(v._token); + } + + once(v, "ended", playbackEnded); + once(v, "seeking", seekStarted); + once(v, "seeked", seekEnded); + + startTest(); +} + +// Fetch the media resource using XHR so we can be sure the entire +// resource is loaded before we test buffered ranges. This ensures +// we have deterministic behaviour. +function fetch(url, fetched_callback) { + var xhr = new XMLHttpRequest(); + xhr.open("GET", url, true); + xhr.responseType = "blob"; + + var loaded = function (event) { + if (xhr.status == 200 || xhr.status == 206) { + // Request fulfilled. Note sometimes we get 206... Presumably because either + // httpd.js or Necko cached the result. + fetched_callback(window.URL.createObjectURL(xhr.response)); + } else { + ok(false, "Fetch failed headers=" + xhr.getAllResponseHeaders()); + } + }; + + xhr.addEventListener("load", loaded, false); + xhr.send(); +} + +function startTest(test, token) { + var onfetched = function(uri) { + var v = document.createElement('video'); + v._token = token; + v.src = uri; + v.addEventListener("loadeddata", testWebM1, false); + document.body.appendChild(v); + } + manager.started(token); + fetch(test.name, onfetched); +} + +SimpleTest.waitForExplicitFinish(); +manager.runTests(gCuelessWebMTests, startTest); + +</script> +</pre> +</body> +</html> \ No newline at end of file
new file mode 100644 --- /dev/null +++ b/dom/media/test/test_cueless_webm_seek-2.html @@ -0,0 +1,126 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=657791 +--> +<head> + <title>Test for Bug 657791</title> + <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> + <script type="text/javascript" src="manifest.js"></script> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=657791">Mozilla Bug 657791</a> + +<p id="display"></p> +<div id="content" style="display: none"> + +</div> +<pre id="test"> +<script type="application/javascript"> + +// Subset of seek tests for cueless WebMs. When random seeking (rather than just +// in buffered ranges) is implemented for WebM, these tests can be removed and +// the cueless WebM(s) references can be moved to the general test_seek test +// array. +// Test array is defined in manifest.js + +var manager = new MediaTestManager; + +// Exercise functionality as in test_seek-2 +function testWebM2(e) { + var v = e.target; + v.removeEventListener('loadeddata', testWebM2); + + var startPassed = false; + var endPassed = false; + var completed = false; + + ok(v.buffered.length >= 1, "Should have a buffered range"); + var halfBuffered = v.buffered.end(0) / 2; + + function startTest() { + if (completed) + return; + + is(v.seekable.start(0), v.buffered.start(0), "Seekable start should be buffered start"); + is(v.seekable.end(0), v.buffered.end(0), "Seekable end should be buffered end"); + v.currentTime=halfBuffered; + v.play(); + } + + function seekStarted() { + if (completed) + return; + + startPassed = true; + } + + function seekEnded() { + if (completed) + return; + + endPassed = true; + } + + function playbackEnded() { + if (completed) + return; + + completed = true; + ok(startPassed, "send seeking event"); + ok(endPassed, "send seeked event"); + ok(v.ended, "Checking playback has ended"); + ok(Math.abs(v.currentTime - v.duration) <= 0.1, "Checking currentTime at end: " + v.currentTime); + removeNodeAndSource(v); + manager.finished(v._token); + } + + v.addEventListener("ended", playbackEnded, false); + v.addEventListener("seeking", seekStarted, false); + v.addEventListener("seeked", seekEnded, false); + + startTest(); +} + +// Fetch the media resource using XHR so we can be sure the entire +// resource is loaded before we test buffered ranges. This ensures +// we have deterministic behaviour. +function fetch(url, fetched_callback) { + var xhr = new XMLHttpRequest(); + xhr.open("GET", url, true); + xhr.responseType = "blob"; + + var loaded = function (event) { + if (xhr.status == 200 || xhr.status == 206) { + // Request fulfilled. Note sometimes we get 206... Presumably because either + // httpd.js or Necko cached the result. + fetched_callback(window.URL.createObjectURL(xhr.response)); + } else { + ok(false, "Fetch failed headers=" + xhr.getAllResponseHeaders()); + } + }; + + xhr.addEventListener("load", loaded, false); + xhr.send(); +} + +function startTest(test, token) { + var onfetched = function(uri) { + var v = document.createElement('video'); + v._token = token; + v.src = uri; + v.addEventListener("loadeddata", testWebM2, false); + document.body.appendChild(v); + } + manager.started(token); + fetch(test.name, onfetched); +} + +SimpleTest.waitForExplicitFinish(); +manager.runTests(gCuelessWebMTests, startTest); + +</script> +</pre> +</body> +</html> \ No newline at end of file
new file mode 100644 --- /dev/null +++ b/dom/media/test/test_cueless_webm_seek-3.html @@ -0,0 +1,122 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=657791 +--> +<head> + <title>Test for Bug 657791</title> + <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> + <script type="text/javascript" src="manifest.js"></script> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=657791">Mozilla Bug 657791</a> + +<p id="display"></p> +<div id="content" style="display: none"> + +</div> +<pre id="test"> +<script type="application/javascript"> + +// Subset of seek tests for cueless WebMs. When random seeking (rather than just +// in buffered ranges) is implemented for WebM, these tests can be removed and +// the cueless WebM(s) references can be moved to the general test_seek test +// array. +// Test array is defined in manifest.js + +var manager = new MediaTestManager; + +// Exercise functionality as in test_seek-3 +function testWebM3(e) { + var v = e.target; + v.removeEventListener('loadeddata', testWebM3); + + var startPassed = false; + var completed = false; + var gotTimeupdate = false; + + ok(v.buffered.length >= 1, "Should have a buffered range"); + var halfBuffered = v.buffered.end(0) / 2; + + function startTest() { + if (completed) + return; + + is(v.seekable.start(0), v.buffered.start(0), "Seekable start should be buffered start"); + is(v.seekable.end(0), v.buffered.end(0), "Seekable end should be buffered end"); + v.currentTime=halfBuffered; + } + + function timeupdate() { + gotTimeupdate = true; + v.removeEventListener("timeupdate", timeupdate, false); + } + + function seekStarted() { + if (completed) + return; + + v.addEventListener("timeupdate", timeupdate, false); + startPassed = true; + } + + function seekEnded() { + if (completed) + return; + + var t = v.currentTime; + ok(Math.abs(t - halfBuffered) <= 0.1, "Video currentTime should be around " + halfBuffered + ": " + t); + ok(gotTimeupdate, "Should have got timeupdate between seeking and seekended"); + completed = true; + removeNodeAndSource(v); + manager.finished(v._token); + } + + v.addEventListener("seeking", seekStarted, false); + v.addEventListener("seeked", seekEnded, false); + + startTest() +} + +// Fetch the media resource using XHR so we can be sure the entire +// resource is loaded before we test buffered ranges. This ensures +// we have deterministic behaviour. +function fetch(url, fetched_callback) { + var xhr = new XMLHttpRequest(); + xhr.open("GET", url, true); + xhr.responseType = "blob"; + + var loaded = function (event) { + if (xhr.status == 200 || xhr.status == 206) { + // Request fulfilled. Note sometimes we get 206... Presumably because either + // httpd.js or Necko cached the result. + fetched_callback(window.URL.createObjectURL(xhr.response)); + } else { + ok(false, "Fetch failed headers=" + xhr.getAllResponseHeaders()); + } + }; + + xhr.addEventListener("load", loaded, false); + xhr.send(); +} + +function startTest(test, token) { + var onfetched = function(uri) { + var v = document.createElement('video'); + v._token = token; + v.src = uri; + v.addEventListener("loadeddata", testWebM3, false); + document.body.appendChild(v); + } + manager.started(token); + fetch(test.name, onfetched); +} + +SimpleTest.waitForExplicitFinish(); +manager.runTests(gCuelessWebMTests, startTest); + +</script> +</pre> +</body> +</html> \ No newline at end of file
--- a/dom/media/webm/WebMBufferedParser.cpp +++ b/dom/media/webm/WebMBufferedParser.cpp @@ -327,26 +327,32 @@ bool WebMBufferedState::CalculateBuffere *aEndTime = mTimeMapping[end].mTimecode + frameDuration; return true; } bool WebMBufferedState::GetOffsetForTime(uint64_t aTime, int64_t* aOffset) { ReentrantMonitorAutoEnter mon(mReentrantMonitor); + if(mTimeMapping.IsEmpty()) { + return false; + } + uint64_t time = aTime; if (time > 0) { time = time - 1; } uint32_t idx = mTimeMapping.IndexOfFirstElementGt(time, TimeComparator()); if (idx == mTimeMapping.Length()) { - return false; + // Clamp to end + *aOffset = mTimeMapping[mTimeMapping.Length() - 1].mSyncOffset; + } else { + // Idx is within array or has been clamped to start + *aOffset = mTimeMapping[idx].mSyncOffset; } - - *aOffset = mTimeMapping[idx].mSyncOffset; return true; } void WebMBufferedState::NotifyDataArrived(const unsigned char* aBuffer, uint32_t aLength, int64_t aOffset) { uint32_t idx = mRangeParsers.IndexOfFirstElementGt(aOffset - 1); if (idx == 0 || !(mRangeParsers[idx-1] == aOffset)) { // If the incoming data overlaps an already parsed range, adjust the
--- a/dom/media/webm/WebMBufferedParser.h +++ b/dom/media/webm/WebMBufferedParser.h @@ -274,19 +274,21 @@ public: } void NotifyDataArrived(const unsigned char* aBuffer, uint32_t aLength, int64_t aOffset); void Reset(); void UpdateIndex(const MediaByteRangeSet& aRanges, MediaResource* aResource); bool CalculateBufferedForRange(int64_t aStartOffset, int64_t aEndOffset, uint64_t* aStartTime, uint64_t* aEndTime); - // Returns true if aTime is is present in mTimeMapping and sets aOffset to + // Returns true if mTimeMapping is not empty and sets aOffset to // the latest offset for which decoding can resume without data - // dependencies to arrive at aTime. + // dependencies to arrive at aTime. aTime will be clamped to the start + // of mTimeMapping if it is earlier than the first element, and to the end + // if later than the last bool GetOffsetForTime(uint64_t aTime, int64_t* aOffset); // Returns end offset of init segment or -1 if none found. int64_t GetInitEndOffset(); // Returns the end offset of the last complete block or -1 if none found. int64_t GetLastBlockOffset(); // Returns start time
--- a/dom/media/webm/WebMDemuxer.cpp +++ b/dom/media/webm/WebMDemuxer.cpp @@ -429,16 +429,22 @@ WebMDemuxer::ReadMetadata() } bool WebMDemuxer::IsSeekable() const { return mContext && nestegg_has_cues(mContext); } +bool +WebMDemuxer::IsSeekableOnlyInBufferedRanges() const +{ + return mContext && !nestegg_has_cues(mContext); +} + void WebMDemuxer::EnsureUpToDateIndex() { if (!mNeedReIndex || !mInitData) { return; } AutoPinned<MediaResource> resource(mResource.GetResource()); MediaByteRangeSet byteRanges;
--- a/dom/media/webm/WebMDemuxer.h +++ b/dom/media/webm/WebMDemuxer.h @@ -93,16 +93,18 @@ public: UniquePtr<TrackInfo> GetTrackInfo(TrackInfo::TrackType aType, size_t aTrackNumber) const; already_AddRefed<MediaTrackDemuxer> GetTrackDemuxer(TrackInfo::TrackType aType, uint32_t aTrackNumber) override; bool IsSeekable() const override; + bool IsSeekableOnlyInBufferedRanges() const override; + UniquePtr<EncryptionInfo> GetCrypto() override; bool GetOffsetForTime(uint64_t aTime, int64_t* aOffset); // Demux next WebM packet and append samples to MediaRawDataQueue bool GetNextPacket(TrackInfo::TrackType aType, MediaRawDataQueue *aSamples); nsresult Reset();
--- a/dom/plugins/ipc/PluginModuleParent.cpp +++ b/dom/plugins/ipc/PluginModuleParent.cpp @@ -2360,18 +2360,18 @@ PluginModuleChromeParent::RecvNP_Initial } } else if (aError == NPERR_NO_ERROR) { // Initialization steps for (e10s && !asyncInit) || !e10s #if defined XP_WIN if (mIsStartingAsync) { SetPluginFuncs(mNPPIface); } - // Send the info needed to join the chrome process's audio session to the - // plugin process + // Send the info needed to join the browser process's audio session to the + // plugin process. nsID id; nsString sessionName; nsString iconPath; if (NS_SUCCEEDED(mozilla::widget::GetAudioSessionData(id, sessionName, iconPath))) { Unused << SendSetAudioSessionData(id, sessionName, iconPath); }
--- a/dom/tests/mochitest/general/test_interfaces.html +++ b/dom/tests/mochitest/general/test_interfaces.html @@ -793,19 +793,19 @@ var interfaceNamesInGlobalScope = "MouseEvent", // IMPORTANT: Do not change this list without review from a DOM peer! "MouseScrollEvent", // IMPORTANT: Do not change this list without review from a DOM peer! {name: "MozActivity", b2g: true}, // IMPORTANT: Do not change this list without review from a DOM peer! {name: "MozClirModeEvent", b2g: true}, // IMPORTANT: Do not change this list without review from a DOM peer! - "mozContact", -// IMPORTANT: Do not change this list without review from a DOM peer! - "MozContactChangeEvent", + {name: "mozContact", b2g: true, permission: "contacts-read"}, +// IMPORTANT: Do not change this list without review from a DOM peer! + {name: "MozContactChangeEvent", b2g: true, permission: "contacts-read"}, // IMPORTANT: Do not change this list without review from a DOM peer! "MozCSSKeyframeRule", // IMPORTANT: Do not change this list without review from a DOM peer! "MozCSSKeyframesRule", // IMPORTANT: Do not change this list without review from a DOM peer! {name: "MozEmergencyCbModeEvent", b2g: true}, // IMPORTANT: Do not change this list without review from a DOM peer! {name: "MozInputContext", b2g: true, permission: ["input"]}, @@ -821,17 +821,17 @@ var interfaceNamesInGlobalScope = {name: "MozMobileConnectionInfo", b2g: true}, // IMPORTANT: Do not change this list without review from a DOM peer! {name: "MozMobileNetworkInfo", b2g: true}, // IMPORTANT: Do not change this list without review from a DOM peer! {name: "MozNDEFRecord", b2g: true}, // IMPORTANT: Do not change this list without review from a DOM peer! {name: "MozOtaStatusEvent", b2g: true}, // IMPORTANT: Do not change this list without review from a DOM peer! - "MozPowerManager", + {name: "MozPowerManager", b2g: true, permission: "power"}, // IMPORTANT: Do not change this list without review from a DOM peer! "mozRTCIceCandidate", // IMPORTANT: Do not change this list without review from a DOM peer! "mozRTCPeerConnection", // IMPORTANT: Do not change this list without review from a DOM peer! "mozRTCSessionDescription", // IMPORTANT: Do not change this list without review from a DOM peer! "MozSettingsEvent",
--- a/dom/webidl/AnimationEffectTiming.webidl +++ b/dom/webidl/AnimationEffectTiming.webidl @@ -7,24 +7,24 @@ * https://w3c.github.io/web-animations/#animationeffecttiming * * Copyright © 2015 W3C® (MIT, ERCIM, Keio), All Rights Reserved. W3C * liability, trademark and document use rules apply. */ [Func="nsDocument::IsWebAnimationsEnabled"] interface AnimationEffectTiming : AnimationEffectTimingReadOnly { - //Bug 1244633 - implement AnimationEffectTiming delay - //inherit attribute double delay; - inherit attribute double endDelay; - //Bug 1244637 - implement AnimationEffectTiming fill - //inherit attribute FillMode fill; - //Bug 1244638 - implement AnimationEffectTiming iterationStart - //inherit attribute double iterationStart; - //Bug 1244640 - implement AnimationEffectTiming iterations - //inherit attribute unrestricted double iterations; + //Bug 1244633 - implement AnimationEffectTiming delay + //inherit attribute double delay; + inherit attribute double endDelay; + //Bug 1244637 - implement AnimationEffectTiming fill + //inherit attribute FillMode fill; + [SetterThrows] + inherit attribute double iterationStart; + //Bug 1244640 - implement AnimationEffectTiming iterations + //inherit attribute unrestricted double iterations; [SetterThrows] inherit attribute (unrestricted double or DOMString) duration; - //Bug 1244642 - implement AnimationEffectTiming direction - //inherit attribute PlaybackDirection direction; - //Bug 1244643 - implement AnimationEffectTiming easing - //inherit attribute DOMString easing; + //Bug 1244642 - implement AnimationEffectTiming direction + //inherit attribute PlaybackDirection direction; + //Bug 1244643 - implement AnimationEffectTiming easing + //inherit attribute DOMString easing; };
--- a/dom/webidl/Contacts.webidl +++ b/dom/webidl/Contacts.webidl @@ -53,17 +53,18 @@ dictionary ContactProperties { sequence<DOMString>? category; sequence<DOMString>? org; sequence<DOMString>? jobTitle; sequence<DOMString>? note; sequence<DOMString>? key; }; [Constructor(optional ContactProperties properties), - JSImplementation="@mozilla.org/contact;1"] + JSImplementation="@mozilla.org/contact;1", + CheckAnyPermissions="contacts-read contacts-write contacts-create"] interface mozContact { attribute DOMString id; readonly attribute Date? published; readonly attribute Date? updated; attribute Date? bday; attribute Date? anniversary; @@ -111,17 +112,18 @@ dictionary ContactFindSortOptions { dictionary ContactFindOptions : ContactFindSortOptions { DOMString filterValue; // e.g. "Tom" DOMString filterOp; // e.g. "startsWith" any filterBy; // e.g. ["givenName", "nickname"] unsigned long filterLimit = 0; }; [NoInterfaceObject, NavigatorProperty="mozContacts", - JSImplementation="@mozilla.org/contactManager;1"] + JSImplementation="@mozilla.org/contactManager;1", + CheckAnyPermissions="contacts-read contacts-write contacts-create"] interface ContactManager : EventTarget { DOMRequest find(optional ContactFindOptions options); DOMCursor getAll(optional ContactFindSortOptions options); DOMRequest clear(); DOMRequest save(mozContact contact); DOMRequest remove((mozContact or DOMString) contactOrId); DOMRequest getRevision(); DOMRequest getCount();
--- a/dom/webidl/MozContactChangeEvent.webidl +++ b/dom/webidl/MozContactChangeEvent.webidl @@ -1,15 +1,16 @@ /* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* 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/. */ -[Constructor(DOMString type, optional MozContactChangeEventInit eventInitDict)] +[Constructor(DOMString type, optional MozContactChangeEventInit eventInitDict), + CheckAnyPermissions="contacts-read contacts-write contacts-create"] interface MozContactChangeEvent : Event { readonly attribute DOMString? contactID; readonly attribute DOMString? reason; }; dictionary MozContactChangeEventInit : EventInit {
--- a/dom/webidl/MozPowerManager.webidl +++ b/dom/webidl/MozPowerManager.webidl @@ -16,16 +16,17 @@ enum FactoryResetReason { "normal", "wipe", "root" }; /** * This interface implements navigator.mozPower */ +[CheckAnyPermissions="power"] interface MozPowerManager { [Throws] void powerOff(); [Throws] void reboot(); void factoryReset(optional FactoryResetReason reason = "normal");
--- a/js/src/asmjs/WasmIonCompile.cpp +++ b/js/src/asmjs/WasmIonCompile.cpp @@ -1434,26 +1434,16 @@ EmitHeapAddress(FunctionCompiler& f, MDe bool accessNeedsBoundsCheck = true; if (endOffset > f.mirGen().foldableOffsetRange(accessNeedsBoundsCheck)) { MDefinition* rhs = f.constant(Int32Value(offset), MIRType_Int32); *base = f.binary<MAdd>(*base, rhs, MIRType_Int32); offset = 0; access->setOffset(offset); } - // TODO Remove this after implementing unaligned loads/stores. - int32_t maskVal = ~(Scalar::byteSize(access->accessType()) - 1); - if (maskVal == -1) - return true; - - offset &= maskVal; - access->setOffset(offset); - - MDefinition* mask = f.constant(Int32Value(maskVal), MIRType_Int32); - *base = f.bitwise<MBitAnd>(*base, mask, MIRType_Int32); return true; } static bool EmitLoad(FunctionCompiler& f, Scalar::Type viewType, MDefinition** def) { MDefinition* base; MAsmJSHeapAccess access(viewType);
--- a/js/src/asmjs/WasmSignalHandlers.cpp +++ b/js/src/asmjs/WasmSignalHandlers.cpp @@ -725,16 +725,43 @@ EmulateHeapAccess(EMULATOR_CONTEXT* cont case Disassembler::HeapAccess::Unknown: MOZ_CRASH("Failed to disassemble instruction"); } } return end; } +#elif defined(ASMJS_MAY_USE_SIGNAL_HANDLERS_FOR_UNALIGNED) + +MOZ_COLD static uint8_t* +EmulateHeapAccess(EMULATOR_CONTEXT* context, uint8_t* pc, uint8_t* faultingAddress, + const HeapAccess* heapAccess, const Module& module) +{ + // TODO: Implement unaligned accesses. + return module.outOfBounds(); +} + +#endif // defined(ASMJS_MAY_USE_SIGNAL_HANDLERS_FOR_UNALIGNED) + +#if defined(ASMJS_MAY_USE_SIGNAL_HANDLERS) + +MOZ_COLD static bool +IsHeapAccessAddress(const Module &module, uint8_t* faultingAddress) +{ +#if defined(ASMJS_MAY_USE_SIGNAL_HANDLERS_FOR_OOB) + size_t accessLimit = MappedSize; +#elif defined(ASMJS_MAY_USE_SIGNAL_HANDLERS_FOR_UNALIGNED) + size_t accessLimit = module.heapLength(); +#endif + return module.usesHeap() && + faultingAddress >= module.heap() && + faultingAddress < module.heap() + accessLimit; +} + #if defined(XP_WIN) static bool HandleFault(PEXCEPTION_POINTERS exception) { EXCEPTION_RECORD* record = exception->ExceptionRecord; CONTEXT* context = exception->ContextRecord; @@ -754,25 +781,22 @@ HandleFault(PEXCEPTION_POINTERS exceptio AutoSetHandlingSegFault handling(rt); WasmActivation* activation = rt->wasmActivationStack(); if (!activation) return false; const Module& module = activation->module(); - // These checks aren't necessary, but, since we can, check anyway to make + uint8_t* faultingAddress = reinterpret_cast<uint8_t*>(record->ExceptionInformation[1]); + + // This check isn't necessary, but, since we can, check anyway to make // sure we aren't covering up a real bug. - uint8_t* faultingAddress = reinterpret_cast<uint8_t*>(record->ExceptionInformation[1]); - if (!module.usesHeap() || - faultingAddress < module.heap() || - faultingAddress >= module.heap() + MappedSize) - { + if (!IsHeapAccessAddress(module, faultingAddress)) return false; - } if (!module.containsFunctionPC(pc)) { // On Windows, it is possible for InterruptRunningCode to execute // between a faulting heap access and the handling of the fault due // to InterruptRunningCode's use of SuspendThread. When this happens, // after ResumeThread, the exception handler is called with pc equal to // module.interrupt, which is logically wrong. The Right Thing would // be for the OS to make fault-handling atomic (so that CONTEXT.pc was @@ -899,25 +923,22 @@ HandleMachException(JSRuntime* rt, const WasmActivation* activation = rt->wasmActivationStack(); if (!activation) return false; const Module& module = activation->module(); if (!module.containsFunctionPC(pc)) return false; - // These checks aren't necessary, but, since we can, check anyway to make + uint8_t* faultingAddress = reinterpret_cast<uint8_t*>(request.body.code[1]); + + // This check isn't necessary, but, since we can, check anyway to make // sure we aren't covering up a real bug. - uint8_t* faultingAddress = reinterpret_cast<uint8_t*>(request.body.code[1]); - if (!module.usesHeap() || - faultingAddress < module.heap() || - faultingAddress >= module.heap() + MappedSize) - { + if (!IsHeapAccessAddress(module, faultingAddress)) return false; - } const HeapAccess* heapAccess = module.lookupHeapAccess(pc); if (!heapAccess) return false; *ppc = EmulateHeapAccess(&context, pc, faultingAddress, heapAccess, module); // Update the thread state with the new pc and register values. @@ -1109,25 +1130,22 @@ HandleFault(int signum, siginfo_t* info, WasmActivation* activation = rt->wasmActivationStack(); if (!activation) return false; const Module& module = activation->module(); if (!module.containsFunctionPC(pc)) return false; - // These checks aren't necessary, but, since we can, check anyway to make + uint8_t* faultingAddress = reinterpret_cast<uint8_t*>(info->si_addr); + + // This check isn't necessary, but, since we can, check anyway to make // sure we aren't covering up a real bug. - uint8_t* faultingAddress = reinterpret_cast<uint8_t*>(info->si_addr); - if (!module.usesHeap() || - faultingAddress < module.heap() || - faultingAddress >= module.heap() + MappedSize) - { + if (!IsHeapAccessAddress(module, faultingAddress)) return false; - } const HeapAccess* heapAccess = module.lookupHeapAccess(pc); if (!heapAccess) return false; *ppc = EmulateHeapAccess(context, pc, faultingAddress, heapAccess, module); return true; @@ -1157,17 +1175,17 @@ AsmJSFaultHandler(int signum, siginfo_t* sPrevSEGVHandler.sa_sigaction(signum, info, context); else if (sPrevSEGVHandler.sa_handler == SIG_DFL || sPrevSEGVHandler.sa_handler == SIG_IGN) sigaction(signum, &sPrevSEGVHandler, nullptr); else sPrevSEGVHandler.sa_handler(signum); } #endif -#endif // defined(ASMJS_MAY_USE_SIGNAL_HANDLERS_FOR_OOB) +#endif // defined(ASMJS_MAY_USE_SIGNAL_HANDLERS) static void RedirectIonBackedgesToInterruptCheck(JSRuntime* rt) { if (jit::JitRuntime* jitRuntime = rt->jitRuntime()) { // If the backedge list is being mutated, the pc must be in C++ code and // thus not in a JIT iloop. We assume that the interrupt flag will be // checked at least once before entering JIT code (if not, no big deal; @@ -1218,17 +1236,17 @@ JitInterruptHandler(int signum, siginfo_ rt->finishHandlingJitInterrupt(); } } #endif bool wasm::EnsureSignalHandlersInstalled(JSRuntime* rt) { -#if defined(XP_DARWIN) && defined(ASMJS_MAY_USE_SIGNAL_HANDLERS_FOR_OOB) +#if defined(XP_DARWIN) && defined(ASMJS_MAY_USE_SIGNAL_HANDLERS) // On OSX, each JSRuntime gets its own handler thread. if (!rt->wasmMachExceptionHandler.installed() && !rt->wasmMachExceptionHandler.install(rt)) return false; #endif // All the rest of the handlers are process-wide and thus must only be // installed once. We assume that there are no races creating the first // JSRuntime of the process. @@ -1275,19 +1293,19 @@ wasm::EnsureSignalHandlersInstalled(JSRu // doing to avoid problematic interference. if ((prev.sa_flags & SA_SIGINFO && prev.sa_sigaction) || (prev.sa_handler != SIG_DFL && prev.sa_handler != SIG_IGN)) { MOZ_CRASH("contention for interrupt signal"); } #endif // defined(XP_WIN) -#if defined(ASMJS_MAY_USE_SIGNAL_HANDLERS_FOR_OOB) +#if defined(ASMJS_MAY_USE_SIGNAL_HANDLERS) // Install a SIGSEGV handler to handle safely-out-of-bounds asm.js heap - // access. + // access and/or unaligned accesses. # if defined(XP_WIN) if (!AddVectoredExceptionHandler(/* FirstHandler = */ true, AsmJSFaultHandler)) return false; # elif defined(XP_DARWIN) // OSX handles seg faults via the Mach exception handler above, so don't // install AsmJSFaultHandler. # else // SA_NODEFER allows us to reenter the signal handler if we crash while @@ -1295,17 +1313,17 @@ wasm::EnsureSignalHandlersInstalled(JSRu // handlingSegFault. struct sigaction faultHandler; faultHandler.sa_flags = SA_SIGINFO | SA_NODEFER; faultHandler.sa_sigaction = &AsmJSFaultHandler; sigemptyset(&faultHandler.sa_mask); if (sigaction(SIGSEGV, &faultHandler, &sPrevSEGVHandler)) MOZ_CRASH("unable to install segv handler"); # endif -#endif // defined(ASMJS_MAY_USE_SIGNAL_HANDLERS_FOR_OOB) +#endif // defined(ASMJS_MAY_USE_SIGNAL_HANDLERS) sResult = true; return true; } // JSRuntime::requestInterrupt sets interrupt_ (which is checked frequently by // C++ code at every Baseline JIT loop backedge) and jitStackLimit_ (which is // checked at every Baseline and Ion JIT function prologue). The remaining @@ -1358,8 +1376,25 @@ js::InterruptRunningJitCode(JSRuntime* r #else // On Unix, we instead deliver an async signal to the main thread which // halts the thread and callers our JitInterruptHandler (which has already // been installed by EnsureSignalHandlersInstalled). pthread_t thread = (pthread_t)rt->ownerThreadNative(); pthread_kill(thread, sInterruptSignal); #endif } + +MOZ_COLD bool +js::wasm::IsPCInWasmCode(void *pc) +{ + JSRuntime* rt = RuntimeForCurrentThread(); + if (!rt) + return false; +