Merge mozilla-central to mozilla-inbound

This commit is contained in:
Ed Morley 2012-11-27 19:39:16 +00:00
commit 6aa8ba56de
41 changed files with 1799 additions and 208 deletions

View File

@ -0,0 +1,20 @@
{
"config_version": 1,
"tooltool_manifest": "releng-otoro.tt",
"mock_target": "mozilla-centos6-i386",
"mock_packages": ["ccache", "make", "bison", "flex", "gcc", "g++", "mpfr", "zlib-devel", "ncurses-devel", "zip", "autoconf213", "glibc-static", "perl-Digest-SHA", "wget", "alsa-lib", "atk", "cairo", "dbus-glib", "fontconfig", "freetype", "glib2", "gtk2", "libXRender", "libXt", "pango", "mozilla-python27-mercurial", "openssh-clients", "nss-devel"],
"mock_files": [["/home/cltbld/.ssh", "/home/mock_mozilla/.ssh"]],
"build_targets": [],
"upload_files": [
"{workdir}/out/target/product/otoro/*.img",
"{objdir}/dist/b2g-update/*.mar",
"{objdir}/dist/b2g-*.tar.gz",
"{objdir}/dist/b2g-*.crashreporter-symbols.zip",
"{workdir}/sources.xml"
],
"env": {
"VARIANT": "user",
"B2GUPDATER": "1"
},
"gaia": {"vcs": "hgtool", "repo": "http://hg.mozilla.org/projects/gaia"}
}

View File

@ -0,0 +1,8 @@
[
{
"size": 868355892,
"digest": "0ccae39ee8910947fe3cf51fa3a45e820d2ff11571f6ccec29d9b3e5ae7f7709c1ad657210fbfea98baadd032c3d6a58e00ddbb2e93acafd751089869a72fed6",
"algorithm": "sha512",
"filename": "gonk.tar.xz"
}
]

View File

@ -0,0 +1,108 @@
<?xml version="1.0" ?><manifest>
<!-- This is only a record of which revisions were pulled to generate the
gonk.tar.xz snapshot referred to by releng-otoro.tt -->
<remote fetch="https://android.googlesource.com/" name="aosp"/>
<remote fetch="git://github.com/mozilla-b2g/" name="b2g"/>
<remote fetch="git://github.com/mozilla/" name="mozilla"/>
<remote fetch="git://codeaurora.org/" name="caf"/>
<remote fetch="git://android.git.linaro.org/" name="linaro"/>
<default remote="caf" revision="ics_chocolate_rb4.2" sync-j="4"/>
<!-- Gonk specific things and forks -->
<project name="platform_build" path="build" remote="b2g" revision="273ba23d5c6c9f6a34995a3cc429804d1449ca9f">
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="2f4377622f4c40275546c7816c0d4b21e800b4c6"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="32106d4ea635ebe17a1610b643b398db639b8b97"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="b7911c064a71a5c18e2c92f869f6364a798b46cd"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="6ee1f8987ef36d688f97064c003ad57849dfadf2"/>
<!-- Stock Android things -->
<!-- Information: platform/abi/cpp is tagged with AU_LINUX_GECKO_ICS_STRAWBERRY.01.00.00.19.117 --><project name="platform/abi/cpp" path="abi/cpp" revision="6426040f1be4a844082c9769171ce7f5341a5528"/>
<!-- Information: platform/bionic is tagged with M8960AAAAANLYA100715A --><project name="platform/bionic" path="bionic" revision="cd5dfce80bc3f0139a56b58aca633202ccaee7f8"/>
<!-- Information: platform/bootable/recovery is tagged with M8960AAAAANLYA100715A --><project name="platform/bootable/recovery" path="bootable/recovery" revision="e0a9ac010df3afaa47ba107192c05ac8b5516435"/>
<!-- Information: platform/development is tagged with M8960AAAAANLYA100715A --><project name="platform/development" path="development" revision="a384622f5fcb1d2bebb9102591ff7ae91fe8ed2d"/>
<!-- Information: device/common is tagged with M8960AAAAANLYA1005304 --><project name="device/common" path="device/common" revision="7c65ea240157763b8ded6154a17d3c033167afb7"/>
<!-- Information: device/sample is tagged with M8960AAAAANLYA100715A --><project name="device/sample" path="device/sample" revision="c328f3d4409db801628861baa8d279fb8855892f"/>
<!-- Information: platform/external/apache-http is tagged with AU_LINUX_GECKO_ICS_STRAWBERRY.01.00.00.19.117 --><project name="platform/external/apache-http" path="external/apache-http" revision="6c9d8c58d3ed710f87c26820d903bb8aad81754f"/>
<!-- Information: platform/external/bluetooth/bluez is tagged with M76XXUSNEKNLYA2040 --><project name="platform/external/bluetooth/bluez" path="external/bluetooth/bluez" revision="1023c91c66e9c3bd1132480051993bf7827770f6"/>
<!-- Information: platform/external/bluetooth/glib is tagged with AU_LINUX_GECKO_ICS_STRAWBERRY.01.00.00.19.117 --><project name="platform/external/bluetooth/glib" path="external/bluetooth/glib" revision="c6b49241cc1a8950723a5f74f8f4b4f4c3fa970e"/>
<!-- Information: platform/external/bluetooth/hcidump is tagged with M8960AAAAANLYA1005304 --><project name="platform/external/bluetooth/hcidump" path="external/bluetooth/hcidump" revision="02b1eb24fbb3d0135a81edb4a2175b1397308d7d"/>
<!-- Information: platform/external/bsdiff is tagged with A8064AAAAANLYA1334 --><project name="platform/external/bsdiff" path="external/bsdiff" revision="81872540236d9bb15cccf963d05b9de48baa5375"/>
<!-- Information: platform/external/bzip2 is tagged with AU_LINUX_GECKO_ICS_STRAWBERRY.01.00.00.19.117 --><project name="platform/external/bzip2" path="external/bzip2" revision="048dacdca43eed1534689ececcf2781c63e1e4ba"/>
<!-- Information: platform/external/dbus is tagged with M8960AAAAANLYA100715A --><project name="platform/external/dbus" path="external/dbus" revision="c7517b6195dc6926728352113e6cc335da3f9c9e"/>
<!-- Information: platform/external/dhcpcd is tagged with M8960AAAAANLYA100715A --><project name="platform/external/dhcpcd" path="external/dhcpcd" revision="1e00fb67022d0921af0fead263f81762781b9ffa"/>
<!-- Information: platform/external/dnsmasq is tagged with A8064AAAAANLYA1334 --><project name="platform/external/dnsmasq" path="external/dnsmasq" revision="f621afad94df46204c25fc2593a19d704d2637f5"/>
<!-- Information: platform/external/e2fsprogs is tagged with AU_LINUX_GECKO_ICS_STRAWBERRY.01.00.00.19.117 --><project name="platform/external/e2fsprogs" path="external/e2fsprogs" revision="d5f550bb2f556c5d287f7c8d2b77223654bcec37"/>
<!-- Information: platform/external/expat is tagged with AU_LINUX_GECKO_ICS_STRAWBERRY.01.00.00.19.117 --><project name="platform/external/expat" path="external/expat" revision="6df134250feab71edb5915ecaa6268210bca76c5"/>
<!-- Information: platform/external/fdlibm is tagged with AU_LINUX_GECKO_ICS_STRAWBERRY.01.00.00.19.117 --><project name="platform/external/fdlibm" path="external/fdlibm" revision="988ffeb12a6e044ae3504838ef1fee3fe0716934"/>
<!-- Information: platform/external/flac is tagged with AU_LINUX_GECKO_ICS_STRAWBERRY.01.00.00.19.117 --><project name="platform/external/flac" path="external/flac" revision="5893fbe890f5dab8e4146d2baa4bd2691c0739e0"/>
<!-- Information: platform/external/freetype is tagged with AU_LINUX_GECKO_ICS_STRAWBERRY.01.00.00.19.117 --><project name="platform/external/freetype" path="external/freetype" revision="aeb407daf3711a10a27f3bc2223c5eb05158076e"/>
<!-- Information: platform/external/giflib is tagged with A8064AAAAANLYA1334 --><project name="platform/external/giflib" path="external/giflib" revision="b2597268aef084202a8c349d1cc072c03c6e22eb"/>
<!-- Information: platform/external/gtest is tagged with android-4.2_r1 --><project name="platform/external/gtest" path="external/gtest" remote="linaro" revision="344e5f3db17615cc853073a02968a603efd39109"/>
<!-- Information: platform/external/harfbuzz is tagged with AU_LINUX_GECKO_ICS_STRAWBERRY.01.00.00.19.117 --><project name="platform/external/harfbuzz" path="external/harfbuzz" revision="116610d63a859521dacf00fb6818ee9ab2e666f6"/>
<!-- Information: platform/external/icu4c is tagged with AU_LINUX_GECKO_ICS_STRAWBERRY.01.00.00.19.117 --><project name="platform/external/icu4c" path="external/icu4c" revision="0fa67b93b831c6636ca18b152a1b1b14cc99b034"/>
<!-- Information: platform/external/iptables is tagged with AU_LINUX_GECKO_ICS_STRAWBERRY.01.00.00.19.117 --><project name="platform/external/iptables" path="external/iptables" revision="3b2deb17f065c5664bb25e1a28489e5792eb63ff"/>
<!-- Information: platform/external/jhead is tagged with AU_LINUX_GECKO_ICS_STRAWBERRY.01.00.00.19.117 --><project name="platform/external/jhead" path="external/jhead" revision="754078052c687f6721536009c816644c73e4f145"/>
<!-- Information: platform/external/jpeg is tagged with M8960AAAAANLYA1005304 --><project name="platform/external/jpeg" path="external/jpeg" revision="a62e464d672a4623233180e4023034bf825f066e"/>
<!-- Information: platform/external/libgsm is tagged with A8064AAAAANLYA1334 --><project name="platform/external/libgsm" path="external/libgsm" revision="5e4516958690b9a1b2c98f88eeecba3edd2dbda4"/>
<!-- Information: platform/external/liblzf is tagged with A8064AAAAANLYA1334 --><project name="platform/external/liblzf" path="external/liblzf" revision="6946aa575b0949d045722794850896099d937cbb"/>
<!-- Information: platform/external/libnfc-nxp is tagged with AU_LINUX_GECKO_ICS_STRAWBERRY.01.00.00.19.117 --><project name="platform/external/libnfc-nxp" path="external/libnfc-nxp" revision="3a912b065a31a72c63ad56ac224cfeaa933423b6"/>
<!-- Information: platform/external/libnl-headers is tagged with A8064AAAAANLYA1334 --><project name="platform/external/libnl-headers" path="external/libnl-headers" revision="6ccf7349d61f73ac26a0675d735d903ab919c658"/>
<!-- Information: platform/external/libphonenumber is tagged with AU_LINUX_GECKO_ICS_STRAWBERRY.01.00.00.19.117 --><project name="platform/external/libphonenumber" path="external/libphonenumber" revision="8d22c9a05eda1935c6dc27d188158e6ee38dc016"/>
<!-- Information: platform/external/libpng is tagged with M8960AAAAANLYA100715A --><project name="platform/external/libpng" path="external/libpng" revision="9c3730f0efa69f580f03463c237cd928f3196404"/>
<!-- Information: platform/external/libvpx is tagged with AU_LINUX_GECKO_ICS_STRAWBERRY.01.00.00.19.117 --><project name="platform/external/libvpx" path="external/libvpx" revision="3a40da0d96da5c520e7707aa14f48a80956e20d7"/>
<!-- Information: platform/external/llvm is tagged with M8960AAAAANLYA1005304 --><project name="platform/external/llvm" path="external/llvm" revision="bff5923831940309f7d8ddbff5826ca6ed2dc050"/>
<!-- Information: platform/external/mksh is tagged with M8960AAAAANLYA1005304 --><project name="platform/external/mksh" path="external/mksh" revision="ec646e8f5e7dac9a77d1de549c6ed92c04d0cd4b"/>
<project name="platform_external_opensans" path="external/opensans" remote="b2g" revision="b5b4c226ca1d71e936153cf679dda6d3d60e2354"/>
<!-- Information: platform/external/openssl is tagged with AU_LINUX_ANDROID_ICS.04.00.04.00.110 --><project name="platform/external/openssl" path="external/openssl" revision="27d333cce9a31c806b4bfa042925f045c727aecd"/>
<!-- Information: platform/external/protobuf is tagged with A8064AAAAANLYA1334 --><project name="platform/external/protobuf" path="external/protobuf" revision="e217977611c52bccde7f7c78e1d3c790c6357431"/>
<!-- Information: platform/external/safe-iop is tagged with A8064AAAAANLYA1334 --><project name="platform/external/safe-iop" path="external/safe-iop" revision="07073634e2e3aa4f518e36ed5dec3aabc549d5fb"/>
<project name="screencap-gonk" path="external/screencap-gonk" remote="b2g" revision="e6403c71e9eca8cb943739d5a0a192deac60fc51"/>
<!-- Information: platform/external/skia is tagged with M8960AAAAANLYA100715A --><project name="platform/external/skia" path="external/skia" revision="7d90c85f2c0e3b747f7c7eff8bc9253b0063b439"/>
<!-- Information: platform/external/sonivox is tagged with M8960AAAAANLYA1005304 --><project name="platform/external/sonivox" path="external/sonivox" revision="7c967779dfc61ac1f346e972de91d4bfce7dccbb"/>
<!-- Information: platform/external/speex is tagged with A8064AAAAANLYA1334 --><project name="platform/external/speex" path="external/speex" revision="ebe6230a7f7c69f5a4389f2b09b7b19ef9e94f32"/>
<project name="platform/external/sqlite" path="external/sqlite" revision="fb30e613139b8836fdc8e81e166cf3a76e5fa17f"/>
<!-- Information: platform/external/stlport is tagged with AU_LINUX_GECKO_ICS_STRAWBERRY.01.00.00.19.117 --><project name="platform/external/stlport" path="external/stlport" revision="a6734e0645fce81c9610de0488b729207bfa576e"/>
<!-- Information: platform/external/strace is tagged with AU_LINUX_GECKO_ICS_STRAWBERRY.01.00.00.19.117 --><project name="platform/external/strace" path="external/strace" revision="c9fd2e5ef7d002e12e7cf2512506c84a9414b0fd"/>
<!-- Information: platform/external/tagsoup is tagged with A8064AAAAANLYA1334 --><project name="platform/external/tagsoup" path="external/tagsoup" revision="68c2ec9e0acdb3214b7fb91dbab8c9fab8736817"/>
<!-- Information: platform/external/tinyalsa is tagged with M8960AAAAANLYA1005304 --><project name="platform/external/tinyalsa" path="external/tinyalsa" revision="06cc244ee512c1352215e543615738bc8ac82814"/>
<!-- Information: platform/external/tremolo is tagged with A8064AAAAANLYA1334 --><project name="platform/external/tremolo" path="external/tremolo" revision="25bd78d2392dbdc879ae53382cde9d019f79cf6f"/>
<project name="unbootimg" path="external/unbootimg" remote="b2g" revision="9464623d92eb8668544916dc5a8f4f6337d0bc08"/>
<!-- Information: platform/external/webp is tagged with A8064AAAAANLYA1334 --><project name="platform/external/webp" path="external/webp" revision="88fe2b83c4b9232cd08729556fd0485d6a6a92cd"/>
<!-- Information: platform/external/webrtc is tagged with AU_LINUX_GECKO_ICS_STRAWBERRY.01.00.00.19.117 --><project name="platform/external/webrtc" path="external/webrtc" revision="137024dc8a2e9251a471e20518a9c3ae06f81f23"/>
<!-- Information: platform/external/wpa_supplicant is tagged with AU_LINUX_GECKO_ICS_STRAWBERRY.01.00.00.19.117 --><project name="platform/external/wpa_supplicant" path="external/wpa_supplicant" revision="a01d37870bbf9892d43e792e5de0683ca41c5497"/>
<!-- Information: platform/external/hostap is tagged with M8960AAAAANLYA1047 --><project name="platform/external/hostap" path="external/hostap" revision="bf04b0faadbdeb4b7943f2e2c4c5aa59df872bb1"/>
<!-- Information: platform/external/zlib is tagged with AU_LINUX_GECKO_ICS_STRAWBERRY.01.00.00.19.117 --><project name="platform/external/zlib" path="external/zlib" revision="f96a1d1ebfdf1cd582210fd09c23d8f59e0ae094"/>
<!-- Information: platform/external/yaffs2 is tagged with AU_LINUX_GECKO_ICS_STRAWBERRY.01.00.00.19.117 --><project name="platform/external/yaffs2" path="external/yaffs2" revision="0afa916204c664b3114429637b63af1321a0aeca"/>
<!-- Information: platform/frameworks/base is tagged with M76XXUSNEKNLYA2040 --><project name="platform/frameworks/base" path="frameworks/base" revision="eb2bc75803ca179353c24c364a9c8a8ce23e8b78"/>
<!-- Information: platform/frameworks/opt/emoji is tagged with AU_LINUX_GECKO_ICS_STRAWBERRY.01.00.00.19.117 --><project name="platform/frameworks/opt/emoji" path="frameworks/opt/emoji" revision="a95d8db002770469d72dfaf59ff37ac96db29a87"/>
<!-- Information: platform/frameworks/support is tagged with M8960AAAAANLYA1005304 --><project name="platform/frameworks/support" path="frameworks/support" revision="27208692b001981f1806f4f396434f4eac78b909"/>
<!-- Information: platform/hardware/libhardware is tagged with M8960AAAAANLYA1049B --><project name="platform/hardware/libhardware" path="hardware/libhardware" revision="4a619901847621f8a7305edf42dd07347a140484"/>
<!-- Information: platform/hardware/libhardware_legacy is tagged with M8960AAAAANLYA153611 --><project name="platform/hardware/libhardware_legacy" path="hardware/libhardware_legacy" revision="87b4d7afa8f854b445e2d0d95091f6f6069f2b30"/>
<!-- Information: platform/libcore is tagged with M8960AAAAANLYA100715A --><project name="platform/libcore" path="libcore" revision="30841f9fba9ccd5c54f4f079f495994db97f283e"/>
<!-- Information: platform/ndk is tagged with AU_LINUX_GECKO_ICS_STRAWBERRY.01.00.00.19.117 --><project name="platform/ndk" path="ndk" revision="9f555971e1481854d5b4dc11b3e6af9fff4f241f"/>
<!-- Information: platform/prebuilt is tagged with M8960AAAAANLYA1005304 --><project name="platform/prebuilt" path="prebuilt" revision="447ea790fcc957dde59730ecc2a65ca263bdc733"/>
<!-- Information: platform/system/bluetooth is tagged with M8960AAAAANLYA100703 --><project name="platform/system/bluetooth" path="system/bluetooth" revision="7772cad4823f1f427ce1d4df84a55982386d6d18"/>
<!-- Information: platform/system/core is tagged with M76XXUSNEKNLYA2040 --><project name="platform/system/core" path="system/core" revision="bf1970408676ce570b8f4dc3efa038e47552137f"/>
<!-- Information: platform/system/extras is tagged with M8960AAAAANLYA1005304 --><project name="platform/system/extras" path="system/extras" revision="01db6c1254e1407740a543f24317fc540fc4c049"/>
<!-- Information: platform/system/media is tagged with M8960AAAAANLYA1005304 --><project name="platform/system/media" path="system/media" revision="7f71c7fd362bbd992ff2e0e80f7af5859ad116ad"/>
<!-- Information: platform/system/netd is tagged with M8960AAAAANLYA1049 --><project name="platform/system/netd" path="system/netd" revision="306e765248e3900041bf2737e9f57b1b5694a4ce"/>
<!-- Information: platform/system/vold is tagged with M8960AAAAANLYA100715A --><project name="platform/system/vold" path="system/vold" revision="99fff257d53cc045d1460841edca5d901dacfcf5"/>
<!-- Otoro/Unagi specific things -->
<!-- Information: device/qcom/common is tagged with M8960AAAAANLYA100715A --><project name="device/qcom/common" path="device/qcom/common" revision="b9cdab8e1e1a215a8c65b8d5816f666bec7be205"/>
<!-- Information: platform/vendor/qcom/msm7627a is tagged with M8960AAAAANLYA100715A --><project name="platform/vendor/qcom/msm7627a" path="device/qcom/msm7627a" revision="d920a502ba17cf4d716f8b1a615f07e796b0501a"/>
<project name="android-device-otoro" path="device/qcom/otoro" remote="b2g" revision="e3e99b264dd0230108aa78f2b653db4ce0e494fb"/>
<project name="android-device-unagi" path="device/qcom/unagi" remote="b2g" revision="f8ca54267ed2ceabefadf96b6953814ac89c5056"/>
<project name="codeaurora_kernel_msm" path="kernel" remote="b2g" revision="0a01247e4b0880f93424b27251cd3a1f6b19dbb2"/>
<!-- Information: platform/hardware/qcom/camera is tagged with M76XXUSNEKNLYA2040 --><project name="platform/hardware/qcom/camera" path="hardware/qcom/camera" revision="1acf77a75e30f3fc8b1eed2057c97adf1cb1633f"/>
<project name="hardware_qcom_display" path="hardware/qcom/display" remote="b2g" revision="6405d30f2fac7d8a1f2cb17b99fb7dd0a8bcfdac"/>
<!-- Information: platform/hardware/qcom/media is tagged with M8960AAAAANLYA100715A --><project name="platform/hardware/qcom/media" path="hardware/qcom/media" revision="552c3ddb7174a01f3508782d40c4d8c845ab441a"/>
<!-- Information: platform/hardware/qcom/gps is tagged with M8960AAAAANLYA100705 --><project name="platform/hardware/qcom/gps" path="hardware/qcom/gps" revision="23d5707b320d7fc69f8ba3b7d84d78a1c5681708"/>
<!-- Information: platform/hardware/msm7k is tagged with AU_LINUX_GECKO_ICS_STRAWBERRY.01.00.00.19.117 --><project name="platform/hardware/msm7k" path="hardware/msm7k" revision="8892d46805c5639b55dd07547745c5180da861e7"/>
<!-- Information: platform/vendor/qcom-opensource/omx/mm-core is tagged with M8960AAAAANLYA100715A --><project name="platform/vendor/qcom-opensource/omx/mm-core" path="vendor/qcom/opensource/omx/mm-core" revision="ab17ac9a074b4bb69986a8436336bdfbbaf9cd39"/>
<!-- Information: platform/hardware/ril is tagged with M76XXUSNEKNLYA1610 --><project name="platform/hardware/ril" path="hardware/ril" remote="caf" revision="fe9a3f63922143b57e79ed570bab2328df8c83a5"/>
</manifest>

View File

@ -136,6 +136,7 @@ XPCOMUtils.defineLazyGetter(this, "Tilt", function() {
XPCOMUtils.defineLazyModuleGetter(this, "Social",
"resource:///modules/Social.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "PageThumbs",
"resource:///modules/PageThumbs.jsm");

View File

@ -509,7 +509,7 @@ StackFrames.prototype = {
// If an error was thrown during the evaluation of the watch expressions,
// then at least one expression evaluation could not be performed.
if (this.currentEvaluation.throw) {
DebuggerView.WatchExpressions.removeExpression(0);
DebuggerView.WatchExpressions.removeExpressionAt(0);
DebuggerController.StackFrames.syncWatchExpressions();
return;
}
@ -600,11 +600,15 @@ StackFrames.prototype = {
// If watch expressions evaluation results are available, create a scope
// to contain all the values.
if (watchExpressionsEvaluation) {
if (this.syncedWatchExpressions && watchExpressionsEvaluation) {
let label = L10N.getStr("watchExpressionsScopeLabel");
let arrow = L10N.getStr("watchExpressionsSeparatorLabel");
let scope = DebuggerView.Variables.addScope(label);
scope.separator = arrow;
scope.allowNameInput = true;
scope.allowDeletion = true;
scope.switch = DebuggerView.WatchExpressions.switchExpression;
scope.delete = DebuggerView.WatchExpressions.deleteExpression;
// The evaluation hasn't thrown, so display the returned results and
// always expand the watch expressions scope by default.
@ -939,6 +943,7 @@ StackFrames.prototype = {
this.syncedWatchExpressions =
this.currentWatchExpressions = null;
}
this.currentFrame = null;
this._onFrames();
},
@ -1321,11 +1326,10 @@ Breakpoints.prototype = {
this.activeThread.setBreakpoint(aLocation, function(aResponse, aBreakpointClient) {
let { url, line } = aResponse.actualLocation || aLocation;
// Prevent this new breakpoint from being repositioned on top of an
// already existing one.
// If the response contains a breakpoint that exists in the cache, prevent
// it from being shown in the source editor at an incorrect position.
if (this.getBreakpoint(url, line)) {
this._hideBreakpoint(aBreakpointClient);
aBreakpointClient.remove();
return;
}

View File

@ -945,6 +945,8 @@ create({ constructor: BreakpointsView, proto: MenuContainer.prototype }, {
function WatchExpressionsView() {
dumpn("WatchExpressionsView was instantiated");
MenuContainer.call(this);
this.switchExpression = this.switchExpression.bind(this);
this.deleteExpression = this.deleteExpression.bind(this);
this._createItemView = this._createItemView.bind(this);
this._onClick = this._onClick.bind(this);
this._onClose = this._onClose.bind(this);
@ -1028,11 +1030,54 @@ create({ constructor: WatchExpressionsView, proto: MenuContainer.prototype }, {
* @param number aIndex
* The index used to identify the watch expression.
*/
removeExpression: function DVWE_removeExpression(aIndex) {
removeExpressionAt: function DVWE_removeExpressionAt(aIndex) {
this.remove(this._cache[aIndex]);
this._cache.splice(aIndex, 1);
},
/**
* Changes the watch expression corresponding to the specified variable item.
*
* @param Variable aVar
* The variable representing the watch expression evaluation.
* @param string aExpression
* The new watch expression text.
*/
switchExpression: function DVWE_switchExpression(aVar, aExpression) {
let expressionItem =
[i for (i of this._cache) if (i.attachment.expression == aVar.name)][0];
// Remove the watch expression if it's going to be a duplicate.
if (!aExpression || this.getExpressions().indexOf(aExpression) != -1) {
this.deleteExpression(aVar);
return;
}
// Save the watch expression code string.
expressionItem.attachment.expression = aExpression;
expressionItem.target.inputNode.value = aExpression;
// Synchronize with the controller's watch expressions store.
DebuggerController.StackFrames.syncWatchExpressions();
},
/**
* Removes the watch expression corresponding to the specified variable item.
*
* @param Variable aVar
* The variable representing the watch expression evaluation.
*/
deleteExpression: function DVWE_deleteExpression(aVar) {
let expressionItem =
[i for (i of this._cache) if (i.attachment.expression == aVar.name)][0];
// Remove the watch expression at its respective index.
this.removeExpressionAt(this._cache.indexOf(expressionItem));
// Synchronize with the controller's watch expressions store.
DebuggerController.StackFrames.syncWatchExpressions();
},
/**
* Gets the watch expression code string for an item in this container.
*
@ -1101,7 +1146,7 @@ create({ constructor: WatchExpressionsView, proto: MenuContainer.prototype }, {
*/
_onClose: function DVWE__onClose(e) {
let expressionItem = this.getItemForElement(e.target);
this.removeExpression(this._cache.indexOf(expressionItem));
this.removeExpressionAt(this._cache.indexOf(expressionItem));
// Synchronize with the controller's watch expressions store.
DebuggerController.StackFrames.syncWatchExpressions();
@ -1116,15 +1161,15 @@ create({ constructor: WatchExpressionsView, proto: MenuContainer.prototype }, {
_onBlur: function DVWE__onBlur({ target: textbox }) {
let expressionItem = this.getItemForElement(textbox);
let oldExpression = expressionItem.attachment.expression;
let newExpression = textbox.value;
let newExpression = textbox.value.trim();
// Remove the watch expression if it's empty.
if (!newExpression) {
this.removeExpression(this._cache.indexOf(expressionItem));
this.removeExpressionAt(this._cache.indexOf(expressionItem));
}
// Remove the watch expression if it's a duplicate.
else if (!oldExpression && this.getExpressions().indexOf(newExpression) != -1) {
this.removeExpression(this._cache.indexOf(expressionItem));
this.removeExpressionAt(this._cache.indexOf(expressionItem));
}
// Expression is eligible.
else {

View File

@ -34,10 +34,10 @@ ToolbarView.prototype = {
this._chromeGlobals = document.getElementById("chrome-globals");
this._scripts = document.getElementById("sources");
let resumeKey = LayoutHelpers.prettyKey(document.getElementById("resumeKey"));
let stepOverKey = LayoutHelpers.prettyKey(document.getElementById("stepOverKey"));
let stepInKey = LayoutHelpers.prettyKey(document.getElementById("stepInKey"));
let stepOutKey = LayoutHelpers.prettyKey(document.getElementById("stepOutKey"));
let resumeKey = LayoutHelpers.prettyKey(document.getElementById("resumeKey"), true);
let stepOverKey = LayoutHelpers.prettyKey(document.getElementById("stepOverKey"), true);
let stepInKey = LayoutHelpers.prettyKey(document.getElementById("stepInKey"), true);
let stepOutKey = LayoutHelpers.prettyKey(document.getElementById("stepOutKey"), true);
this._resumeTooltip = L10N.getFormatStr("resumeButtonTooltip", [resumeKey]);
this._pauseTooltip = L10N.getFormatStr("pauseButtonTooltip", [resumeKey]);
this._stepOverTooltip = L10N.getFormatStr("stepOverTooltip", [stepOverKey]);
@ -370,6 +370,20 @@ create({ constructor: SourcesView, proto: MenuContainer.prototype }, {
this._container.removeEventListener("click", this._onClick, false);
},
/**
* Sets the preferred source url to be displayed in this container.
* @param string aValue
*/
set preferredSource(aValue) {
this._preferredValue = aValue;
// Selects the element with the specified value in this container,
// if already inserted.
if (this.containsValue(aValue)) {
this.selectedValue = aValue;
}
},
/**
* The select listener for the sources container.
*/
@ -577,11 +591,11 @@ FilterView.prototype = {
this._variableOperatorButton = document.getElementById("variable-operator-button");
this._variableOperatorLabel = document.getElementById("variable-operator-label");
this._globalSearchKey = LayoutHelpers.prettyKey(document.getElementById("globalSearchKey"));
this._fileSearchKey = LayoutHelpers.prettyKey(document.getElementById("fileSearchKey"));
this._lineSearchKey = LayoutHelpers.prettyKey(document.getElementById("lineSearchKey"));
this._tokenSearchKey = LayoutHelpers.prettyKey(document.getElementById("tokenSearchKey"));
this._variableSearchKey = LayoutHelpers.prettyKey(document.getElementById("variableSearchKey"));
this._fileSearchKey = LayoutHelpers.prettyKey(document.getElementById("fileSearchKey"), true);
this._globalSearchKey = LayoutHelpers.prettyKey(document.getElementById("globalSearchKey"), true);
this._tokenSearchKey = LayoutHelpers.prettyKey(document.getElementById("tokenSearchKey"), true);
this._lineSearchKey = LayoutHelpers.prettyKey(document.getElementById("lineSearchKey"), true);
this._variableSearchKey = LayoutHelpers.prettyKey(document.getElementById("variableSearchKey"), true);
this._searchbox.addEventListener("click", this._onClick, false);
this._searchbox.addEventListener("select", this._onSearch, false);
@ -879,7 +893,7 @@ FilterView.prototype = {
// Perform a global search based on the specified operator.
if (isGlobal) {
if (isReturnKey && isDifferentToken) {
if (isReturnKey && (isDifferentToken || DebuggerView.GlobalSearch.hidden)) {
DebuggerView.GlobalSearch.performSearch(token);
} else {
DebuggerView.GlobalSearch[["focusNextMatch", "focusPrevMatch"][action]]();
@ -934,10 +948,10 @@ FilterView.prototype = {
},
/**
* Called when the source line filter key sequence was pressed.
* Called when the global search filter key sequence was pressed.
*/
_doLineSearch: function DVF__doLineSearch() {
this._doSearch(SEARCH_LINE_FLAG);
_doGlobalSearch: function DVF__doGlobalSearch() {
this._doSearch(SEARCH_GLOBAL_FLAG);
this._searchboxPanel.hidePopup();
},
@ -950,10 +964,10 @@ FilterView.prototype = {
},
/**
* Called when the global search filter key sequence was pressed.
* Called when the source line filter key sequence was pressed.
*/
_doGlobalSearch: function DVF__doGlobalSearch() {
this._doSearch(SEARCH_GLOBAL_FLAG);
_doLineSearch: function DVF__doLineSearch() {
this._doSearch(SEARCH_LINE_FLAG);
this._searchboxPanel.hidePopup();
},
@ -974,10 +988,13 @@ FilterView.prototype = {
_tokenOperatorLabel: null,
_lineOperatorButton: null,
_lineOperatorLabel: null,
_globalSearchKey: "",
_variableOperatorButton: null,
_variableOperatorLabel: null,
_fileSearchKey: "",
_lineSearchKey: "",
_globalSearchKey: "",
_tokenSearchKey: "",
_lineSearchKey: "",
_variableSearchKey: "",
_target: null,
_prevSearchedFile: "",
_prevSearchedLine: -1,

View File

@ -15,8 +15,8 @@ const GLOBAL_SEARCH_LINE_MAX_LENGTH = 300; // chars
const GLOBAL_SEARCH_EXPAND_MAX_RESULTS = 50;
const GLOBAL_SEARCH_ACTION_MAX_DELAY = 1500; // ms
const SEARCH_GLOBAL_FLAG = "!";
const SEARCH_LINE_FLAG = ":";
const SEARCH_TOKEN_FLAG = "#";
const SEARCH_LINE_FLAG = ":";
const SEARCH_VARIABLE_FLAG = "*";
/**

View File

@ -35,12 +35,12 @@
oncommand="DebuggerView.Toolbar._onStepOutPressed()"/>
<command id="fileSearchCommand"
oncommand="DebuggerView.Filtering._doFileSearch()"/>
<command id="lineSearchCommand"
oncommand="DebuggerView.Filtering._doLineSearch()"/>
<command id="tokenSearchCommand"
oncommand="DebuggerView.Filtering._doTokenSearch()"/>
<command id="globalSearchCommand"
oncommand="DebuggerView.Filtering._doGlobalSearch()"/>
<command id="tokenSearchCommand"
oncommand="DebuggerView.Filtering._doTokenSearch()"/>
<command id="lineSearchCommand"
oncommand="DebuggerView.Filtering._doLineSearch()"/>
<command id="variableSearchCommand"
oncommand="DebuggerView.Filtering._doVariableSearch()"/>
<command id="addBreakpointCommand"
@ -73,10 +73,33 @@
<menuseparator/>
<menuitem id="se-cMenu-selectAll"/>
<menuseparator/>
<menuitem id="se-cMenu-find"/>
<menuitem id="se-cMenu-findAgain"/>
<menuitem id="se-dbg-cMenu-findFile"
label="&debuggerUI.searchFile;"
accesskey="&debuggerUI.searchFile.key;"
key="fileSearchKey"
command="fileSearchCommand"/>
<menuitem id="se-dbg-cMenu-findGlobal"
label="&debuggerUI.searchGlobal;"
accesskey="&debuggerUI.searchGlobal.key;"
key="globalSearchKey"
command="globalSearchCommand"/>
<menuseparator/>
<menuitem id="se-cMenu-gotoLine"/>
<menuitem id="se-dbg-cMenu-findToken"
label="&debuggerUI.searchToken;"
accesskey="&debuggerUI.searchToken.key;"
key="tokenSearchKey"
command="tokenSearchCommand"/>
<menuitem id="se-dbg-cMenu-findLine"
label="&debuggerUI.searchLine;"
accesskey="&debuggerUI.searchLine.key;"
key="lineSearchKey"
command="lineSearchCommand"/>
<menuseparator/>
<menuitem id="se-dbg-cMenu-findVariable"
label="&debuggerUI.searchVariable;"
accesskey="&debuggerUI.searchVariable.key;"
key="variableSearchKey"
command="variableSearchCommand"/>
</menupopup>
<menupopup id="debuggerPrefsContextMenu"
position="before_end"
@ -105,48 +128,46 @@
</menupopup>
</popupset>
<keyset id="sourceEditorKeys"/>
<keyset id="debuggerKeys">
<key id="resumeKey"
keycode="VK_F6"
keycode="&debuggerUI.stepping.resume;"
command="resumeCommand"/>
<key id="stepOverKey"
keycode="VK_F7"
keycode="&debuggerUI.stepping.stepOver;"
command="stepOverCommand"/>
<key id="stepInKey"
keycode="VK_F8"
keycode="&debuggerUI.stepping.stepIn;"
command="stepInCommand"/>
<key id="stepOutKey"
keycode="VK_F8"
keycode="&debuggerUI.stepping.stepOut;"
modifiers="shift"
command="stepOutCommand"/>
<key id="fileSearchKey"
key="P"
modifiers="control shift"
key="&debuggerUI.searchFile.key;"
modifiers="accel"
command="fileSearchCommand"/>
<key id="lineSearchKey"
key="G"
modifiers="control shift"
command="lineSearchCommand"/>
<key id="tokenSearchKey"
key="T"
modifiers="control shift"
command="tokenSearchCommand"/>
<key id="globalSearchKey"
key="F"
modifiers="control shift"
key="&debuggerUI.searchGlobal.key;"
modifiers="accel alt"
command="globalSearchCommand"/>
<key id="tokenSearchKey"
key="&debuggerUI.searchToken.key;"
modifiers="accel"
command="tokenSearchCommand"/>
<key id="lineSearchKey"
key="&debuggerUI.searchLine.key;"
modifiers="accel"
command="lineSearchCommand"/>
<key id="variableSearchKey"
key="V"
modifiers="control shift"
key="&debuggerUI.searchVariable.key;"
modifiers="accel alt"
command="variableSearchCommand"/>
<key id="addBreakpointKey"
key="B"
key="&debuggerUI.seMenuBreak.key;"
modifiers="accel"
command="addBreakpointCommand"/>
<key id="addConditionalBreakpointKey"
key="B"
key="&debuggerUI.seMenuCondBreak.key;"
modifiers="accel shift"
command="addConditionalBreakpointCommand"/>
</keyset>
@ -181,6 +202,7 @@
<spacer flex="1"/>
<toolbarbutton id="toggle-panes"
class="devtools-toolbarbutton"
tooltiptext="&debuggerUI.panesButton.tooltip;"
tabindex="0"/>
<toolbarbutton id="debugger-options"
class="devtools-option-toolbarbutton"

View File

@ -33,6 +33,7 @@ MOCHITEST_BROWSER_TESTS = \
browser_dbg_propertyview-09.js \
browser_dbg_propertyview-10.js \
browser_dbg_propertyview-edit.js \
browser_dbg_propertyview-edit-watch.js \
browser_dbg_propertyview-data.js \
browser_dbg_propertyview-filter-01.js \
browser_dbg_propertyview-filter-02.js \
@ -44,6 +45,7 @@ MOCHITEST_BROWSER_TESTS = \
browser_dbg_propertyview-filter-08.js \
browser_dbg_propertyview-reexpand.js \
browser_dbg_reload-same-script.js \
browser_dbg_reload-preferred-script.js \
browser_dbg_pane-collapse.js \
browser_dbg_panesize.js \
browser_dbg_panesize-inner.js \

View File

@ -52,6 +52,20 @@ function test()
is(gWatch.getExpressions().length, 1,
"Duplicate watch expressions are automatically removed");
addAndCheckExpressions(2, 0, "a\t", true);
addAndCheckExpressions(2, 0, "a\r", true);
addAndCheckExpressions(2, 0, "a\n", true);
gDebugger.editor.focus();
is(gWatch.getExpressions().length, 1,
"Duplicate watch expressions are automatically removed");
addAndCheckExpressions(2, 0, "\ta", true);
addAndCheckExpressions(2, 0, "\ra", true);
addAndCheckExpressions(2, 0, "\na", true);
gDebugger.editor.focus();
is(gWatch.getExpressions().length, 1,
"Duplicate watch expressions are automatically removed");
addAndCheckCustomExpression(2, 0, "bazΩΩka");
addAndCheckCustomExpression(3, 0, "bambøøcha");
@ -194,7 +208,7 @@ function test()
}
function removeAndCheckExpression(total, index, string) {
gWatch.removeExpression(index);
gWatch.removeExpressionAt(index);
is(gWatch.getExpressions().length, total,
"There should be " + total + " watch expressions available (1)");

View File

@ -97,8 +97,6 @@ function test()
"#editMenuKeys not found");
ok(document.getElementById("sourceEditorCommands"),
"#sourceEditorCommands found");
ok(document.getElementById("sourceEditorKeys"),
"#sourceEditorKeys found");
// Map command ids to their expected disabled state.
let commands = {"se-cmd-undo": true, "se-cmd-redo": true,

View File

@ -0,0 +1,502 @@
/* vim:set ts=2 sw=2 sts=2 et: */
/*
* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/
*/
/**
* Make sure that the editing or removing watch expressions works properly.
*/
const TAB_URL = EXAMPLE_URL + "browser_dbg_watch-expressions.html";
var gPane = null;
var gTab = null;
var gDebuggee = null;
var gDebugger = null;
var gWatch = null;
var gVars = null;
requestLongerTimeout(2);
function test() {
debug_tab_pane(TAB_URL, function(aTab, aDebuggee, aPane) {
gTab = aTab;
gDebuggee = aDebuggee;
gPane = aPane;
gDebugger = gPane.contentWindow;
gWatch = gDebugger.DebuggerView.WatchExpressions;
gVars = gDebugger.DebuggerView.Variables;
gDebugger.DebuggerController.StackFrames.autoScopeExpand = true;
gDebugger.DebuggerView.Variables.nonEnumVisible = false;
testFrameEval();
});
}
function testFrameEval() {
gDebugger.addEventListener("Debugger:FetchedWatchExpressions", function test() {
gDebugger.removeEventListener("Debugger:FetchedWatchExpressions", test, false);
Services.tm.currentThread.dispatch({ run: function() {
is(gDebugger.DebuggerController.activeThread.state, "paused",
"Should only be getting stack frames while paused.");
var localScope = gDebugger.DebuggerView.Variables._list.querySelectorAll(".scope")[1],
localNodes = localScope.querySelector(".details").childNodes,
aArg = localNodes[1],
varT = localNodes[3];
is(aArg.querySelector(".name").getAttribute("value"), "aArg",
"Should have the right name for 'aArg'.");
is(varT.querySelector(".name").getAttribute("value"), "t",
"Should have the right name for 't'.");
is(aArg.querySelector(".value").getAttribute("value"), "undefined",
"Should have the right initial value for 'aArg'.");
is(varT.querySelector(".value").getAttribute("value"), "\"Browser Debugger Watch Expressions Test\"",
"Should have the right initial value for 't'.");
is(gWatch._container._parent.querySelectorAll(".dbg-expression[hidden=true]").length, 5,
"There should be 5 hidden nodes in the watch expressions container");
is(gWatch._container._parent.querySelectorAll(".dbg-expression:not([hidden=true])").length, 0,
"There should be 0 visible nodes in the watch expressions container");
let label = gDebugger.L10N.getStr("watchExpressionsScopeLabel");
let scope = gVars._currHierarchy.get(label);
ok(scope, "There should be a wach expressions scope in the variables view");
is(scope._store.size, 5, "There should be 5 evaluations availalble");
is(scope.get("this")._isShown, true,
"Should have the right visibility state for 'this'.");
is(scope.get("this").target.querySelectorAll(".dbg-variables-delete").length, 1,
"Should have the one close button visible for 'this'.");
is(scope.get("this").name, "this",
"Should have the right name for 'this'.");
is(scope.get("this").value.type, "object",
"Should have the right value type for 'this'.");
is(scope.get("this").value.class, "Proxy",
"Should have the right value type for 'this'.");
is(scope.get("ermahgerd")._isShown, true,
"Should have the right visibility state for 'ermahgerd'.");
is(scope.get("ermahgerd").target.querySelectorAll(".dbg-variables-delete").length, 1,
"Should have the one close button visible for 'ermahgerd'.");
is(scope.get("ermahgerd").name, "ermahgerd",
"Should have the right name for 'ermahgerd'.");
is(scope.get("ermahgerd").value.type, "object",
"Should have the right value type for 'ermahgerd'.");
is(scope.get("ermahgerd").value.class, "Function",
"Should have the right value type for 'ermahgerd'.");
is(scope.get("aArg")._isShown, true,
"Should have the right visibility state for 'aArg'.");
is(scope.get("aArg").target.querySelectorAll(".dbg-variables-delete").length, 1,
"Should have the one close button visible for 'aArg'.");
is(scope.get("aArg").name, "aArg",
"Should have the right name for 'aArg'.");
is(scope.get("aArg").value, undefined,
"Should have the right value for 'aArg'.");
is(scope.get("document.title")._isShown, true,
"Should have the right visibility state for 'document.title'.");
is(scope.get("document.title").target.querySelectorAll(".dbg-variables-delete").length, 1,
"Should have the one close button visible for 'document.title'.");
is(scope.get("document.title").name, "document.title",
"Should have the right name for 'document.title'.");
is(scope.get("document.title").value, "42",
"Should have the right value for 'document.title'.");
is(typeof scope.get("document.title").value, "string",
"Should have the right value type for 'document.title'.");
is(scope.get("document.title = 42")._isShown, true,
"Should have the right visibility state for 'document.title = 42'.");
is(scope.get("document.title = 42").target.querySelectorAll(".dbg-variables-delete").length, 1,
"Should have the one close button visible for 'document.title = 42'.");
is(scope.get("document.title = 42").name, "document.title = 42",
"Should have the right name for 'document.title = 42'.");
is(scope.get("document.title = 42").value, 42,
"Should have the right value for 'document.title = 42'.");
is(typeof scope.get("document.title = 42").value, "number",
"Should have the right value type for 'document.title = 42'.");
testModification(scope.get("document.title = 42").target, test1, function(scope) {
testModification(scope.get("aArg").target, test2, function(scope) {
testModification(scope.get("aArg = 44").target, test3, function(scope) {
testModification(scope.get("document.title = 43").target, test4, function(scope) {
testModification(scope.get("document.title").target, test5, function(scope) {
testExprDeletion(scope.get("this").target, test6, function(scope) {
testExprDeletion(scope.get("ermahgerd").target, test7, function(scope) {
resumeAndFinish();
}, 44, 0, true);
}, 44);
}, " \t\r\n", "\"43\"", 44, 1, true);
}, " \t\r\ndocument.title \t\r\n", "\"43\"", 44);
}, " \t\r\ndocument.title \t\r\n", "\"43\"", 44);
}, "aArg = 44", 44, 44);
}, "document.title = 43", 43, "undefined");
}}, 0);
}, false);
addWatchExpression("this");
addWatchExpression("ermahgerd");
addWatchExpression("aArg");
addWatchExpression("document.title");
addWatchExpression("document.title = 42");
executeSoon(function() {
gDebuggee.ermahgerd(); // ermahgerd!!
});
}
function testModification(aVar, aTest, aCallback, aNewValue, aNewResult, aArgResult,
aLocalScopeIndex = 1, aDeletionFlag = null)
{
function makeChangesAndExitInputMode() {
EventUtils.sendString(aNewValue);
EventUtils.sendKey("RETURN");
}
EventUtils.sendMouseEvent({ type: "dblclick" },
aVar.querySelector(".name"),
gDebugger);
executeSoon(function() {
ok(aVar.querySelector(".element-name-input"),
"There should be an input element created.");
let testContinued = false;
let fetchedVariables = false;
let fetchedExpressions = false;
let countV = 0;
gDebugger.addEventListener("Debugger:FetchedVariables", function testV() {
// We expect 2 Debugger:FetchedVariables events, one from the global
// object scope and the regular one.
if (++countV < 2) {
info("Number of received Debugger:FetchedVariables events: " + countV);
return;
}
gDebugger.removeEventListener("Debugger:FetchedVariables", testV, false);
fetchedVariables = true;
executeSoon(continueTest);
}, false);
let countE = 0;
gDebugger.addEventListener("Debugger:FetchedWatchExpressions", function testE() {
// We expect only one Debugger:FetchedWatchExpressions event, since all
// expressions are evaluated at the same time.
if (++countE < 1) {
info("Number of received Debugger:FetchedWatchExpressions events: " + countE);
return;
}
gDebugger.removeEventListener("Debugger:FetchedWatchExpressions", testE, false);
fetchedExpressions = true;
executeSoon(continueTest);
}, false);
function continueTest() {
if (testContinued || !fetchedVariables || !fetchedExpressions) {
return;
}
testContinued = true;
// Get the variable reference anew, since the old ones were discarded when
// we resumed.
var localScope = gDebugger.DebuggerView.Variables._list.querySelectorAll(".scope")[aLocalScopeIndex],
localNodes = localScope.querySelector(".details").childNodes,
aArg = localNodes[1];
is(aArg.querySelector(".value").getAttribute("value"), aArgResult,
"Should have the right value for 'aArg'.");
let label = gDebugger.L10N.getStr("watchExpressionsScopeLabel");
let scope = gVars._currHierarchy.get(label);
info("Found the watch expressions scope: " + scope);
let aExp = scope.get(aVar.querySelector(".name").getAttribute("value"));
info("Found the watch expression variable: " + aExp);
if (aDeletionFlag) {
ok(fetchedVariables, "The variables should have been fetched.");
ok(fetchedExpressions, "The variables should have been fetched.");
is(aExp, undefined, "The watch expression should not have been found.");
performCallback(scope);
return;
}
is(aExp.target.querySelector(".name").getAttribute("value"), aNewValue.trim(),
"Should have the right name for '" + aNewValue + "'.");
is(aExp.target.querySelector(".value").getAttribute("value"), aNewResult,
"Should have the right value for '" + aNewValue + "'.");
performCallback(scope);
}
makeChangesAndExitInputMode();
});
function performCallback(scope) {
executeSoon(function() {
aTest(scope);
aCallback(scope);
});
}
}
function testExprDeletion(aVar, aTest, aCallback, aArgResult,
aLocalScopeIndex = 1, aFinalFlag = null)
{
let testContinued = false;
let fetchedVariables = false;
let fetchedExpressions = false;
let countV = 0;
gDebugger.addEventListener("Debugger:FetchedVariables", function testV() {
// We expect 2 Debugger:FetchedVariables events, one from the global
// object scope and the regular one.
if (++countV < 2) {
info("Number of received Debugger:FetchedVariables events: " + countV);
return;
}
gDebugger.removeEventListener("Debugger:FetchedVariables", testV, false);
fetchedVariables = true;
executeSoon(continueTest);
}, false);
let countE = 0;
gDebugger.addEventListener("Debugger:FetchedWatchExpressions", function testE() {
// We expect only one Debugger:FetchedWatchExpressions event, since all
// expressions are evaluated at the same time.
if (++countE < 1) {
info("Number of received Debugger:FetchedWatchExpressions events: " + countE);
return;
}
gDebugger.removeEventListener("Debugger:FetchedWatchExpressions", testE, false);
fetchedExpressions = true;
executeSoon(continueTest);
}, false);
function continueTest() {
if ((testContinued || !fetchedVariables || !fetchedExpressions) && !aFinalFlag) {
return;
}
testContinued = true;
// Get the variable reference anew, since the old ones were discarded when
// we resumed.
var localScope = gDebugger.DebuggerView.Variables._list.querySelectorAll(".scope")[aLocalScopeIndex],
localNodes = localScope.querySelector(".details").childNodes,
aArg = localNodes[1];
is(aArg.querySelector(".value").getAttribute("value"), aArgResult,
"Should have the right value for 'aArg'.");
let label = gDebugger.L10N.getStr("watchExpressionsScopeLabel");
let scope = gVars._currHierarchy.get(label);
info("Found the watch expressions scope: " + scope);
if (aFinalFlag) {
ok(fetchedVariables, "The variables should have been fetched.");
ok(!fetchedExpressions, "The variables should never have been fetched.");
is(scope, undefined, "The watch expressions scope should not have been found.");
performCallback(scope);
return;
}
let aExp = scope.get(aVar.querySelector(".name").getAttribute("value"));
info("Found the watch expression variable: " + aExp);
is(aExp, undefined, "Should not have found the watch expression after deletion.");
performCallback(scope);
}
function performCallback(scope) {
executeSoon(function() {
aTest(scope);
aCallback(scope);
});
}
EventUtils.sendMouseEvent({ type: "click" },
aVar.querySelector(".dbg-variables-delete"),
gDebugger);
}
function test1(scope) {
is(gWatch._container._parent.querySelectorAll(".dbg-expression[hidden=true]").length, 5,
"There should be 5 hidden nodes in the watch expressions container");
is(gWatch._container._parent.querySelectorAll(".dbg-expression:not([hidden=true])").length, 0,
"There should be 0 visible nodes in the watch expressions container");
ok(scope, "There should be a wach expressions scope in the variables view");
is(scope._store.size, 5, "There should be 5 evaluations availalble");
is(gWatch._cache[0].target.inputNode.value, "document.title = 43",
"The first textbox input value is not the correct one");
is(gWatch._cache[0].attachment.expression, "document.title = 43",
"The first textbox input value is not the correct one");
is(gWatch._cache[1].target.inputNode.value, "document.title",
"The second textbox input value is not the correct one");
is(gWatch._cache[1].attachment.expression, "document.title",
"The second textbox input value is not the correct one");
is(gWatch._cache[2].target.inputNode.value, "aArg",
"The third textbox input value is not the correct one");
is(gWatch._cache[2].attachment.expression, "aArg",
"The third textbox input value is not the correct one");
is(gWatch._cache[3].target.inputNode.value, "ermahgerd",
"The fourth textbox input value is not the correct one");
is(gWatch._cache[3].attachment.expression, "ermahgerd",
"The fourth textbox input value is not the correct one");
is(gWatch._cache[4].target.inputNode.value, "this",
"The fifth textbox input value is not the correct one");
is(gWatch._cache[4].attachment.expression, "this",
"The fifth textbox input value is not the correct one");
}
function test2(scope) {
is(gWatch._container._parent.querySelectorAll(".dbg-expression[hidden=true]").length, 5,
"There should be 5 hidden nodes in the watch expressions container");
is(gWatch._container._parent.querySelectorAll(".dbg-expression:not([hidden=true])").length, 0,
"There should be 0 visible nodes in the watch expressions container");
ok(scope, "There should be a wach expressions scope in the variables view");
is(scope._store.size, 5, "There should be 5 evaluations availalble");
is(gWatch._cache[0].target.inputNode.value, "document.title = 43",
"The first textbox input value is not the correct one");
is(gWatch._cache[0].attachment.expression, "document.title = 43",
"The first textbox input value is not the correct one");
is(gWatch._cache[1].target.inputNode.value, "document.title",
"The second textbox input value is not the correct one");
is(gWatch._cache[1].attachment.expression, "document.title",
"The second textbox input value is not the correct one");
is(gWatch._cache[2].target.inputNode.value, "aArg = 44",
"The third textbox input value is not the correct one");
is(gWatch._cache[2].attachment.expression, "aArg = 44",
"The third textbox input value is not the correct one");
is(gWatch._cache[3].target.inputNode.value, "ermahgerd",
"The fourth textbox input value is not the correct one");
is(gWatch._cache[3].attachment.expression, "ermahgerd",
"The fourth textbox input value is not the correct one");
is(gWatch._cache[4].target.inputNode.value, "this",
"The fifth textbox input value is not the correct one");
is(gWatch._cache[4].attachment.expression, "this",
"The fifth textbox input value is not the correct one");
}
function test3(scope) {
is(gWatch._container._parent.querySelectorAll(".dbg-expression[hidden=true]").length, 4,
"There should be 4 hidden nodes in the watch expressions container");
is(gWatch._container._parent.querySelectorAll(".dbg-expression:not([hidden=true])").length, 0,
"There should be 0 visible nodes in the watch expressions container");
ok(scope, "There should be a wach expressions scope in the variables view");
is(scope._store.size, 4, "There should be 4 evaluations availalble");
is(gWatch._cache[0].target.inputNode.value, "document.title = 43",
"The first textbox input value is not the correct one");
is(gWatch._cache[0].attachment.expression, "document.title = 43",
"The first textbox input value is not the correct one");
is(gWatch._cache[1].target.inputNode.value, "document.title",
"The second textbox input value is not the correct one");
is(gWatch._cache[1].attachment.expression, "document.title",
"The second textbox input value is not the correct one");
is(gWatch._cache[2].target.inputNode.value, "ermahgerd",
"The third textbox input value is not the correct one");
is(gWatch._cache[2].attachment.expression, "ermahgerd",
"The third textbox input value is not the correct one");
is(gWatch._cache[3].target.inputNode.value, "this",
"The fourth textbox input value is not the correct one");
is(gWatch._cache[3].attachment.expression, "this",
"The fourth textbox input value is not the correct one");
}
function test4(scope) {
is(gWatch._container._parent.querySelectorAll(".dbg-expression[hidden=true]").length, 3,
"There should be 3 hidden nodes in the watch expressions container");
is(gWatch._container._parent.querySelectorAll(".dbg-expression:not([hidden=true])").length, 0,
"There should be 0 visible nodes in the watch expressions container");
ok(scope, "There should be a wach expressions scope in the variables view");
is(scope._store.size, 3, "There should be 3 evaluations availalble");
is(gWatch._cache[0].target.inputNode.value, "document.title",
"The first textbox input value is not the correct one");
is(gWatch._cache[0].attachment.expression, "document.title",
"The first textbox input value is not the correct one");
is(gWatch._cache[1].target.inputNode.value, "ermahgerd",
"The second textbox input value is not the correct one");
is(gWatch._cache[1].attachment.expression, "ermahgerd",
"The second textbox input value is not the correct one");
is(gWatch._cache[2].target.inputNode.value, "this",
"The third textbox input value is not the correct one");
is(gWatch._cache[2].attachment.expression, "this",
"The third textbox input value is not the correct one");
}
function test5(scope) {
is(gWatch._container._parent.querySelectorAll(".dbg-expression[hidden=true]").length, 2,
"There should be 2 hidden nodes in the watch expressions container");
is(gWatch._container._parent.querySelectorAll(".dbg-expression:not([hidden=true])").length, 0,
"There should be 0 visible nodes in the watch expressions container");
ok(scope, "There should be a wach expressions scope in the variables view");
is(scope._store.size, 2, "There should be 2 evaluations availalble");
is(gWatch._cache[0].target.inputNode.value, "ermahgerd",
"The second textbox input value is not the correct one");
is(gWatch._cache[0].attachment.expression, "ermahgerd",
"The second textbox input value is not the correct one");
is(gWatch._cache[1].target.inputNode.value, "this",
"The third textbox input value is not the correct one");
is(gWatch._cache[1].attachment.expression, "this",
"The third textbox input value is not the correct one");
}
function test6(scope) {
is(gWatch._container._parent.querySelectorAll(".dbg-expression[hidden=true]").length, 1,
"There should be 1 hidden nodes in the watch expressions container");
is(gWatch._container._parent.querySelectorAll(".dbg-expression:not([hidden=true])").length, 0,
"There should be 0 visible nodes in the watch expressions container");
ok(scope, "There should be a wach expressions scope in the variables view");
is(scope._store.size, 1, "There should be 1 evaluation availalble");
is(gWatch._cache[0].target.inputNode.value, "ermahgerd",
"The third textbox input value is not the correct one");
is(gWatch._cache[0].attachment.expression, "ermahgerd",
"The third textbox input value is not the correct one");
}
function test7(scope) {
is(gWatch._container._parent.querySelectorAll(".dbg-expression[hidden=true]").length, 0,
"There should be 0 hidden nodes in the watch expressions container");
is(gWatch._container._parent.querySelectorAll(".dbg-expression:not([hidden=true])").length, 0,
"There should be 0 visible nodes in the watch expressions container");
is(scope, undefined, "There should be no watch expressions scope available.");
is(gWatch._cache.length, 0, "The watch expressions cache should be empty.");
}
function addWatchExpression(string) {
gWatch.addExpression(string);
gDebugger.editor.focus();
}
function resumeAndFinish() {
gDebugger.DebuggerController.activeThread.resume(function() {
closeDebuggerAndFinish();
});
}
registerCleanupFunction(function() {
removeTab(gTab);
gPane = null;
gTab = null;
gDebuggee = null;
gDebugger = null;
gWatch = null;
gVars = null;
});

View File

@ -4,6 +4,10 @@
* http://creativecommons.org/publicdomain/zero/1.0/
*/
/**
* Make sure that the editing variables or properties values works properly.
*/
const TAB_URL = EXAMPLE_URL + "browser_dbg_frame-parameters.html";
var gPane = null;
@ -70,7 +74,7 @@ function testModification(aVar, aCallback, aNewValue, aNewResult) {
gDebugger);
executeSoon(function() {
ok(aVar.querySelector(".element-input"),
ok(aVar.querySelector(".element-value-input"),
"There should be an input element created.");
let count = 0;

View File

@ -0,0 +1,79 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Tests if the preferred script is shown when a page is loaded.
*/
const TAB_URL = EXAMPLE_URL + "browser_dbg_script-switching.html";
let gPane = null;
let gTab = null;
let gDebuggee = null;
let gDebugger = null;
let gView = null;
requestLongerTimeout(2);
function test()
{
let expectedScript = "test-script-switching-02.js";
let expectedScriptShown = false;
let scriptShownUrl = null;
let resumed = false;
let testStarted = false;
debug_tab_pane(TAB_URL, function(aTab, aDebuggee, aPane) {
gTab = aTab;
gDebuggee = aDebuggee;
gPane = aPane;
gDebugger = gPane.contentWindow;
gView = gDebugger.DebuggerView;
resumed = true;
gView.Sources.preferredSource = EXAMPLE_URL + expectedScript;
startTest();
});
function onScriptShown(aEvent)
{
expectedScriptShown = aEvent.detail.url.indexOf(expectedScript) != -1;
scriptShownUrl = aEvent.detail.url;
startTest();
}
window.addEventListener("Debugger:SourceShown", onScriptShown);
function startTest()
{
if (expectedScriptShown && resumed && !testStarted) {
window.removeEventListener("Debugger:SourceShown", onScriptShown);
testStarted = true;
Services.tm.currentThread.dispatch({ run: performTest }, 0);
}
}
function performTest()
{
info("Currently preferred script: " + gView.Sources.preferredValue);
info("Currently selected script: " + gView.Sources.selectedValue);
isnot(gView.Sources.preferredValue.indexOf(expectedScript), -1,
"The preferred script url wasn't set correctly.");
isnot(gView.Sources.selectedValue.indexOf(expectedScript), -1,
"The selected script isn't the correct one.");
is(gView.Sources.selectedValue, scriptShownUrl,
"The shown script is not the the correct one.");
closeDebuggerAndFinish();
}
registerCleanupFunction(function() {
removeTab(gTab);
gPane = null;
gTab = null;
gDebuggee = null;
gDebugger = null;
gView = null;
});
}

View File

@ -6,7 +6,8 @@
<!-- Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ -->
<script type="text/javascript">
function ermahgerd() {
function ermahgerd(aArg) {
var t = document.title;
debugger;
(function() {
var a = undefined;

View File

@ -326,10 +326,12 @@ this.LayoutHelpers = LayoutHelpers = {
*
* @param Node aElemKey
* The key element to get the modifiers from.
* @param boolean aAllowCloverleaf
* Pass true to use the cloverleaf symbol instead of a descriptive string.
* @return string
* A prettified and properly separated modifier keys string.
*/
prettyKey: function LH_prettyKey(aElemKey)
prettyKey: function LH_prettyKey(aElemKey, aAllowCloverleaf)
{
let elemString = "";
let elemMod = aElemKey.getAttribute("modifiers");
@ -338,9 +340,12 @@ this.LayoutHelpers = LayoutHelpers = {
if (Services.appinfo.OS == "Darwin") {
// XXX bug 779642 Use "Cmd-" literal vs. cloverleaf meta-key until
// Orion adds variable height lines.
// elemString += PlatformKeys.GetStringFromName("VK_META") +
// PlatformKeys.GetStringFromName("MODIFIER_SEPARATOR");
elemString += "Cmd-";
if (!aAllowCloverleaf) {
elemString += "Cmd-";
} else {
elemString += PlatformKeys.GetStringFromName("VK_META") +
PlatformKeys.GetStringFromName("MODIFIER_SEPARATOR");
}
} else {
elemString += PlatformKeys.GetStringFromName("VK_CONTROL") +
PlatformKeys.GetStringFromName("MODIFIER_SEPARATOR");

View File

@ -20,7 +20,9 @@ this.EXPORTED_SYMBOLS = ["VariablesView", "create"];
* Requires the devtools common.css and debugger.css skin stylesheets.
*
* To allow replacing variable or property values in this view, provide an
* "eval" function property.
* "eval" function property. To allow replacing variable or property values,
* provide a "switch" function. To handle deleting variables or properties,
* provide a "delete" function.
*
* @param nsIDOMNode aParentNode
* The parent node to hold this view.
@ -415,6 +417,8 @@ function Scope(aView, aName, aFlags = {}) {
this.ownerView = aView;
this.eval = aView.eval;
this.switch = aView.switch;
this.delete = aView.delete;
this._store = new Map();
this._init(aName.trim(), aFlags);
@ -635,6 +639,24 @@ Scope.prototype = {
*/
set twisty(aFlag) aFlag ? this.showArrow() : this.hideArrow(),
/**
* Specifies if editing variable or property names is allowed.
* This flag applies non-recursively to the current scope.
*/
allowNameInput: false,
/**
* Specifies if editing variable or property values is allowed.
* This flag applies non-recursively to the current scope.
*/
allowValueInput: true,
/**
* Specifies if removing variables or properties values is allowed.
* This flag applies non-recursively to the current scope.
*/
allowDeletion: false,
/**
* Gets the id associated with this item.
* @return string
@ -917,11 +939,14 @@ Scope.prototype = {
* The variable's descriptor.
*/
function Variable(aScope, aName, aDescriptor) {
this._onClose = this._onClose.bind(this);
this._displayTooltip = this._displayTooltip.bind(this);
this._activateInput = this._activateInput.bind(this);
this._deactivateInput = this._deactivateInput.bind(this);
this._saveInput = this._saveInput.bind(this);
this._onInputKeyPress = this._onInputKeyPress.bind(this);
this._activateNameInput = this._activateNameInput.bind(this);
this._activateValueInput = this._activateValueInput.bind(this);
this._deactivateNameInput = this._deactivateNameInput.bind(this);
this._deactivateValueInput = this._deactivateValueInput.bind(this);
this._onNameInputKeyPress = this._onNameInputKeyPress.bind(this);
this._onValueInputKeyPress = this._onValueInputKeyPress.bind(this);
Scope.call(this, aScope, aName, aDescriptor);
this._setGrip(aDescriptor.value);
@ -1180,6 +1205,12 @@ create({ constructor: Variable, proto: Scope.prototype }, {
separatorLabel.hidden = true;
valueLabel.hidden = true;
}
if (this.ownerView.allowDeletion) {
let closeNode = this._closeNode = document.createElement("toolbarbutton");
closeNode.className = "dbg-variables-delete plain devtools-closebutton";
closeNode.addEventListener("click", this._onClose, false);
this._title.appendChild(closeNode);
}
},
/**
@ -1215,6 +1246,16 @@ create({ constructor: Variable, proto: Scope.prototype }, {
this._target.appendChild(tooltip);
this._target.setAttribute("tooltip", tooltip.id);
if (this.ownerView.allowNameInput) {
this._name.setAttribute("tooltiptext", L10N.getStr("variablesEditableNameTooltip"));
}
if (this.ownerView.allowValueInput) {
this._valueLabel.setAttribute("tooltiptext", L10N.getStr("variablesEditableValueTooltip"));
}
if (this.ownerView.allowDeletion) {
this._closeNode.setAttribute("tooltiptext", L10N.getStr("variablesCloseButtonTooltip"));
}
},
/**
@ -1255,44 +1296,54 @@ create({ constructor: Variable, proto: Scope.prototype }, {
_addEventListeners: function V__addEventListeners() {
this._arrow.addEventListener("mousedown", this.toggle, false);
this._name.addEventListener("mousedown", this.toggle, false);
this._valueLabel.addEventListener("click", this._activateInput, false);
this._name.addEventListener("dblclick", this._activateNameInput, false);
this._valueLabel.addEventListener("click", this._activateValueInput, false);
},
/**
* Makes this variable's value editable.
* The click listener for the close button.
*/
_activateInput: function V__activateInput(e) {
if (!this.eval) {
return;
}
let window = this.window;
let document = this.document;
_onClose: function V__onClose() {
this.hide();
let title = this._title;
let valueLabel = this._valueLabel;
let initialString = this._valueLabel.getAttribute("value");
if (this.delete) {
this.delete(this);
}
},
/**
* Creates a textbox node in place of a label.
*
* @param nsIDOMNode aLabel
* The label to be replaced with a textbox.
* @param string aClassName
* The class to be applied to the textbox.
* @param object aCallbacks
* An object containing the onKeypress and onBlur callbacks.
*/
_activateInput: function V__activateInput(aLabel, aClassName, aCallbacks) {
let initialString = aLabel.getAttribute("value");
// Create a texbox input element which will be shown in the current
// element's value location.
// element's specified label location.
let input = this.document.createElement("textbox");
input.setAttribute("value", initialString);
input.className = "plain element-input";
input.className = "plain " + aClassName;
input.width = this._target.clientWidth;
title.removeChild(valueLabel);
title.appendChild(input);
aLabel.parentNode.replaceChild(input, aLabel);
input.select();
// When the value is a string (displayed as "value"), then we probably want
// to change it to another string in the textbox, so to avoid typing the ""
// again, tackle with the selection bounds just a bit.
if (valueLabel.getAttribute("value").match(/^"[^"]*"$/)) {
if (aLabel.getAttribute("value").match(/^"[^"]*"$/)) {
input.selectionEnd--;
input.selectionStart++;
}
input.addEventListener("keypress", this._onInputKeyPress, false);
input.addEventListener("blur", this._deactivateInput, false);
input.addEventListener("keypress", aCallbacks.onKeypress, false);
input.addEventListener("blur", aCallbacks.onBlur, false);
this._prevExpandable = this.twisty;
this._prevExpanded = this.expanded;
@ -1302,18 +1353,17 @@ create({ constructor: Variable, proto: Scope.prototype }, {
},
/**
* Deactivates this variable's editable mode.
* Removes the textbox node in place of a label.
*
* @param nsIDOMNode aLabel
* The label which was replaced with a textbox.
* @param object aCallbacks
* An object containing the onKeypress and onBlur callbacks.
*/
_deactivateInput: function V__deactivateInput(e) {
let input = e.target;
let title = this._title;
let valueLabel = this._valueLabel;
title.removeChild(input);
title.appendChild(valueLabel);
input.removeEventListener("keypress", this._onInputKeyPress, false);
input.removeEventListener("blur", this._deactivateInput, false);
_deactivateInput: function V__deactivateInput(aLabel, aInput, aCallbacks) {
aInput.parentNode.replaceChild(aLabel, aInput);
aInput.removeEventListener("keypress", aCallbacks.onKeypress, false);
aInput.removeEventListener("blur", aCallbacks.onBlur, false);
this._locked = false;
this.twisty = this._prevExpandable;
@ -1321,37 +1371,123 @@ create({ constructor: Variable, proto: Scope.prototype }, {
},
/**
* Deactivates this variable's editable mode and evaluates a new value.
* Makes this variable's name editable.
*/
_saveInput: function V__saveInput(e) {
let input = e.target;
let valueLabel = this._valueLabel;
let initialString = this._valueLabel.getAttribute("value");
let currentString = input.value;
_activateNameInput: function V__activateNameInput() {
if (!this.ownerView.allowNameInput || !this.switch) {
return;
}
this._activateInput(this._name, "element-name-input", {
onKeypress: this._onNameInputKeyPress,
onBlur: this._deactivateNameInput
});
this._separatorLabel.hidden = true;
this._valueLabel.hidden = true;
},
this._deactivateInput(e);
/**
* Deactivates this variable's editable name mode.
*/
_deactivateNameInput: function V__deactivateNameInput(e) {
this._deactivateInput(this._name, e.target, {
onKeypress: this._onNameInputKeyPress,
onBlur: this._deactivateNameInput
});
this._separatorLabel.hidden = false;
this._valueLabel.hidden = false;
},
/**
* Makes this variable's value editable.
*/
_activateValueInput: function V__activateValueInput() {
if (!this.ownerView.allowValueInput || !this.eval) {
return;
}
this._activateInput(this._valueLabel, "element-value-input", {
onKeypress: this._onValueInputKeyPress,
onBlur: this._deactivateValueInput
});
},
/**
* Deactivates this variable's editable value mode.
*/
_deactivateValueInput: function V__deactivateValueInput(e) {
this._deactivateInput(this._valueLabel, e.target, {
onKeypress: this._onValueInputKeyPress,
onBlur: this._deactivateValueInput
});
},
/**
* Disables this variable prior to a new name switch or value evaluation.
*/
_disable: function V__disable() {
this.twisty = false;
this._separatorLabel.hidden = true;
this._valueLabel.hidden = true;
this._enum.hidden = true;
this._nonenum.hidden = true;
},
/**
* Deactivates this variable's editable mode and callbacks the new name.
*/
_saveNameInput: function V__saveNameInput(e) {
let input = e.target;
let initialString = this._name.getAttribute("value");
let currentString = input.value.trim();
this._deactivateNameInput(e);
if (initialString != currentString) {
this._arrow.setAttribute("invisible", "");
this._separatorLabel.hidden = true;
this._valueLabel.hidden = true;
this._enum.hidden = true;
this._nonenum.hidden = true;
this.eval("(" + this._symbolicName + "=" + currentString + ")");
this._disable();
this._name.value = currentString;
this.switch(this, currentString);
}
},
/**
* The key press listener for this variable's editable mode textbox.
* Deactivates this variable's editable mode and evaluates the new value.
*/
_onInputKeyPress: function V__onInputKeyPress(e) {
_saveValueInput: function V__saveValueInput(e) {
let input = e.target;
let initialString = this._valueLabel.getAttribute("value");
let currentString = input.value.trim();
this._deactivateValueInput(e);
if (initialString != currentString) {
this._disable();
this.eval(this._symbolicName + "=" + currentString);
}
},
/**
* The key press listener for this variable's editable name textbox.
*/
_onNameInputKeyPress: function V__onNameInputKeyPress(e) {
switch(e.keyCode) {
case e.DOM_VK_RETURN:
case e.DOM_VK_ENTER:
this._saveInput(e);
this._saveNameInput(e);
return;
case e.DOM_VK_ESCAPE:
this._deactivateInput(e);
this._deactivateNameInput(e);
return;
}
},
/**
* The key press listener for this variable's editable value textbox.
*/
_onValueInputKeyPress: function V__onValueInputKeyPress(e) {
switch(e.keyCode) {
case e.DOM_VK_RETURN:
case e.DOM_VK_ENTER:
this._saveValueInput(e);
return;
case e.DOM_VK_ESCAPE:
this._deactivateValueInput(e);
return;
}
},
@ -1361,6 +1497,7 @@ create({ constructor: Variable, proto: Scope.prototype }, {
_initialDescriptor: null,
_separatorLabel: null,
_valueLabel: null,
_closeNode: null,
_tooltip: null,
_valueGrip: null,
_valueString: "",
@ -1700,6 +1837,7 @@ XPCOMUtils.defineLazyGetter(L10N, "stringBundle", function() {
/**
* The separator label between the variables or properties name and value.
* This property applies non-recursively to the current scope.
*/
Scope.prototype.separator = L10N.getStr("variablesSeparatorLabel");

View File

@ -35,6 +35,10 @@
- the button that closes the debugger UI. -->
<!ENTITY debuggerUI.closeButton.tooltip "Close">
<!-- LOCALIZATION NOTE (debuggerUI.panesButton.tooltip): This is the tooltip for
- the button that toggles the panes visible or hidden in the debugger UI. -->
<!ENTITY debuggerUI.panesButton.tooltip "Toggle panes">
<!-- LOCALIZATION NOTE (debuggerUI.optsButton.tooltip): This is the tooltip for
- the button that opens up an options context menu for the debugger UI. -->
<!ENTITY debuggerUI.optsButton.tooltip "Debugger Options">
@ -64,6 +68,31 @@
- appears in the filter panel popup as a description. -->
<!ENTITY debuggerUI.searchPanelTitle "Operators">
<!-- LOCALIZATION NOTE (debuggerUI.searchFile): This is the text that appears
- in the source editor's context menu for the scripts search operation. -->
<!ENTITY debuggerUI.searchFile "Filter scripts">
<!ENTITY debuggerUI.searchFile.key "P">
<!-- LOCALIZATION NOTE (debuggerUI.searchGlobal): This is the text that appears
- in the source editor's context menu for the global search operation. -->
<!ENTITY debuggerUI.searchGlobal "Search in all files">
<!ENTITY debuggerUI.searchGlobal.key "F">
<!-- LOCALIZATION NOTE (debuggerUI.searchToken): This is the text that appears
- in the source editor's context menu for the token search operation. -->
<!ENTITY debuggerUI.searchToken "Find">
<!ENTITY debuggerUI.searchToken.key "F">
<!-- LOCALIZATION NOTE (debuggerUI.searchLine): This is the text that appears
- in the source editor's context menu for the line search operation. -->
<!ENTITY debuggerUI.searchLine "Jump to line...">
<!ENTITY debuggerUI.searchLine.key "J">
<!-- LOCALIZATION NOTE (debuggerUI.searchVariable): This is the text that appears
- in the source editor's context menu for the variables search operation. -->
<!ENTITY debuggerUI.searchVariable "Filter variables">
<!ENTITY debuggerUI.searchVariable.key "V">
<!-- LOCALIZATION NOTE (debuggerUI.condBreakPanelTitle): This is the text that
- appears in the conditional breakpoint panel popup as a description. -->
<!ENTITY debuggerUI.condBreakPanelTitle "This breakpoint will stop execution only if the following expression is true">
@ -71,8 +100,19 @@
<!-- LOCALIZATION NOTE (debuggerUI.seMenuBreak): This is the text that
- appears in the source editor context menu for adding a breakpoint. -->
<!ENTITY debuggerUI.seMenuBreak "Add breakpoint">
<!ENTITY debuggerUI.seMenuBreak.key "B">
<!-- LOCALIZATION NOTE (debuggerUI.seMenuCondBreak): This is the text that
- appears in the source editor context menu for adding a conditional
- breakpoint. -->
<!ENTITY debuggerUI.seMenuCondBreak "Add conditional breakpoint">
<!ENTITY debuggerUI.seMenuCondBreak.key "B">
<!-- LOCALIZATION NOTE (debuggerUI.stepping): These are the keycodes that
- control the stepping commands in the debugger (continue, step over,
- step in and step out). -->
<!ENTITY debuggerUI.stepping.resume "VK_F6">
<!ENTITY debuggerUI.stepping.stepOver "VK_F7">
<!ENTITY debuggerUI.stepping.stepIn "VK_F8">
<!ENTITY debuggerUI.stepping.stepOut "VK_F8">

View File

@ -173,6 +173,18 @@ watchExpressionsScopeLabel=Watch expressions
# the global scope.
globalScopeLabel=Global
# LOCALIZATION NOTE (variablesEditableNameTooltip): The text that is displayed
# in the variables list on an item with an editable name.
variablesEditableNameTooltip=Double click to edit
# LOCALIZATION NOTE (variablesEditableValueTooltip): The text that is displayed
# in the variables list on an item with an editable name.
variablesEditableValueTooltip=Click to change value
# LOCALIZATION NOTE (variablesCloseButtonTooltip): The text that is displayed
# in the variables list on an item with which can be removed.
variablesCloseButtonTooltip=Click to remove
# LOCALIZATION NOTE (variablesSeparatorLabel): The text that is displayed
# in the variables list as a separator between the name and value.
variablesSeparatorLabel=:

View File

@ -161,6 +161,10 @@
font-weight: 600;
}
.dbg-stackframe-details {
-moz-padding-start: 4px;
}
/**
* Breakpoints view
*/
@ -209,10 +213,6 @@
-moz-padding-start: 8px;
}
.dbg-expression:last-child {
margin-bottom: 4px;
}
.dbg-expression-arrow {
width: 10px;
height: auto;
@ -236,6 +236,11 @@
min-height: 10px;
}
.dbg-variables-delete:not(:hover) {
-moz-image-region: rect(0, 32px, 16px, 16px);
opacity: 0.5;
}
/**
* Scope element
*/
@ -278,6 +283,7 @@
.variable > .title > .value {
-moz-padding-start: 6px;
-moz-padding-end: 4px;
}
.variable:not([non-header]) > .details {
@ -304,6 +310,7 @@
.property > .title > .value {
-moz-padding-start: 6px;
-moz-padding-end: 4px;
}
.property:not([non-header]) > .details {
@ -373,10 +380,16 @@
* Variables and properties editing
*/
#variables .element-input {
#variables .element-value-input {
-moz-margin-start: 5px !important;
}
#variables .element-name-input {
-moz-margin-start: -1px !important;
color: #048;
font-weight: 600;
}
/**
* Variables and properties searching
*/

View File

@ -163,6 +163,10 @@
font-weight: 600;
}
.dbg-stackframe-details {
-moz-padding-start: 4px;
}
/**
* Breakpoints view
*/
@ -211,10 +215,6 @@
-moz-padding-start: 8px;
}
.dbg-expression:last-child {
margin-bottom: 4px;
}
.dbg-expression-arrow {
width: 10px;
height: auto;
@ -238,6 +238,11 @@
min-height: 10px;
}
.dbg-variables-delete:not(:hover) {
-moz-image-region: rect(0, 32px, 16px, 16px);
opacity: 0.5;
}
/**
* Scope element
*/
@ -280,6 +285,7 @@
.variable > .title > .value {
-moz-padding-start: 6px;
-moz-padding-end: 4px;
}
.variable:not([non-header]) > .details {
@ -306,6 +312,7 @@
.property > .title > .value {
-moz-padding-start: 6px;
-moz-padding-end: 4px;
}
.property:not([non-header]) > .details {
@ -375,10 +382,16 @@
* Variables and properties editing
*/
#variables .element-input {
#variables .element-value-input {
-moz-margin-start: 5px !important;
}
#variables .element-name-input {
-moz-margin-start: -1px !important;
color: #048;
font-weight: 600;
}
/**
* Variables and properties searching
*/

View File

@ -169,6 +169,10 @@
font-weight: 600;
}
.dbg-stackframe-details {
-moz-padding-start: 4px;
}
/**
* Breakpoints view
*/
@ -217,10 +221,6 @@
-moz-padding-start: 8px;
}
.dbg-expression:last-child {
margin-bottom: 4px;
}
.dbg-expression-arrow {
width: 10px;
height: auto;
@ -244,6 +244,11 @@
min-height: 10px;
}
.dbg-variables-delete:not(:hover) {
-moz-image-region: rect(0, 32px, 16px, 16px);
opacity: 0.5;
}
/**
* Scope element
*/
@ -286,6 +291,7 @@
.variable > .title > .value {
-moz-padding-start: 6px;
-moz-padding-end: 4px;
}
.variable:not([non-header]) > .details {
@ -312,6 +318,7 @@
.property > .title > .value {
-moz-padding-start: 6px;
-moz-padding-end: 4px;
}
.property:not([non-header]) > .details {
@ -381,10 +388,16 @@
* Variables and properties editing
*/
#variables .element-input {
#variables .element-value-input {
-moz-margin-start: 5px !important;
}
#variables .element-name-input {
-moz-margin-start: -1px !important;
color: #048;
font-weight: 600;
}
/**
* Variables and properties searching
*/

View File

@ -578,13 +578,21 @@ ThreadActor.prototype = {
inner.setBreakpoint(lines[line][i], bpActor);
codeFound = true;
}
bpActor.addScript(inner, this);
actualLocation = {
url: aLocation.url,
line: line,
column: aLocation.column
};
// If there wasn't already a breakpoint at that line, update the cache
// as well.
if (scriptBreakpoints[line] && scriptBreakpoints[line].actor) {
let existing = scriptBreakpoints[line].actor;
bpActor.onDelete();
delete scriptBreakpoints[oldLine];
return { actor: existing.actorID, actualLocation: actualLocation };
}
bpActor.location = actualLocation;
// Update the cache as well.
scriptBreakpoints[line] = scriptBreakpoints[oldLine];
scriptBreakpoints[line].line = line;
delete scriptBreakpoints[oldLine];

View File

@ -0,0 +1,101 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Make sure that setting a breakpoint twice in a line without bytecodes works
* as expected.
*/
const NUM_BREAKPOINTS = 10;
var gDebuggee;
var gClient;
var gThreadClient;
var gPath = getFilePath('test_breakpoint-12.js');
var gBpActor;
var gCount = 1;
function run_test()
{
initTestDebuggerServer();
gDebuggee = addTestGlobal("test-stack");
gClient = new DebuggerClient(DebuggerServer.connectPipe());
gClient.connect(function () {
attachTestGlobalClientAndResume(gClient,
"test-stack",
function (aResponse, aThreadClient) {
gThreadClient = aThreadClient;
test_child_skip_breakpoint();
});
});
do_test_pending();
}
function test_child_skip_breakpoint()
{
gThreadClient.addOneTimeListener("paused", function (aEvent, aPacket) {
let location = { url: gPath, line: gDebuggee.line0 + 3};
gThreadClient.setBreakpoint(location, function (aResponse, bpClient) {
// Check that the breakpoint has properly skipped forward one line.
do_check_eq(aResponse.actualLocation.url, location.url);
do_check_eq(aResponse.actualLocation.line, location.line + 1);
gBpActor = aResponse.actor;
// Set more breakpoints at the same location.
set_breakpoints(location);
});
});
gDebuggee.eval("var line0 = Error().lineNumber;\n" +
"function foo() {\n" + // line0 + 1
" this.a = 1;\n" + // line0 + 2
" // A comment.\n" + // line0 + 3
" this.b = 2;\n" + // line0 + 4
"}\n" + // line0 + 5
"debugger;\n" + // line0 + 6
"foo();\n"); // line0 + 7
}
// Set many breakpoints at the same location.
function set_breakpoints(location) {
do_check_neq(gCount, NUM_BREAKPOINTS);
gThreadClient.setBreakpoint(location, function (aResponse, bpClient) {
// Check that the breakpoint has properly skipped forward one line.
do_check_eq(aResponse.actualLocation.url, location.url);
do_check_eq(aResponse.actualLocation.line, location.line + 1);
// Check that the same breakpoint actor was returned.
do_check_eq(aResponse.actor, gBpActor);
if (++gCount < NUM_BREAKPOINTS) {
set_breakpoints(location);
return;
}
// After setting all the breakpoints, check that only one has effectively
// remained.
gThreadClient.addOneTimeListener("paused", function (aEvent, aPacket) {
// Check the return value.
do_check_eq(aPacket.type, "paused");
do_check_eq(aPacket.frame.where.url, gPath);
do_check_eq(aPacket.frame.where.line, location.line + 1);
do_check_eq(aPacket.why.type, "breakpoint");
do_check_eq(aPacket.why.actors[0], bpClient.actor);
// Check that the breakpoint worked.
do_check_eq(gDebuggee.a, 1);
do_check_eq(gDebuggee.b, undefined);
gThreadClient.addOneTimeListener("paused", function (aEvent, aPacket) {
// We don't expect any more pauses after the breakpoint was hit once.
do_check_true(false);
});
gThreadClient.resume(function () {
// Give any remaining breakpoints a chance to trigger.
do_timeout(1000, finishClient.bind(null, gClient));
});
});
// Continue until the breakpoint is hit.
gThreadClient.resume();
});
}

View File

@ -45,6 +45,7 @@ tail =
[test_breakpoint-09.js]
[test_breakpoint-10.js]
[test_breakpoint-11.js]
[test_breakpoint-12.js]
[test_listscripts-01.js]
[test_objectgrips-01.js]
[test_objectgrips-02.js]

View File

@ -239,6 +239,22 @@ function getDistributionPrefValue(aPrefName) {
return prefValue;
}
/**
* Parse a string representation of a regular expression. Needed because we
* use the /pattern/flags form (because it's detectable), which is only
* supported as a literal in JS.
*
* @param aStr
* String representation of regexp
* @return RegExp instance
*/
function parseRegExp(aStr) {
let lastSlash = aStr.lastIndexOf("/");
let pattern = aStr.slice(1, lastSlash);
let flags = aStr.slice(lastSlash + 1);
return new RegExp(pattern, flags);
}
/**
* Manages the Blocklist. The Blocklist is a representation of the contents of
* blocklist.xml and allows us to remotely disable / re-enable blocklisted
@ -342,11 +358,11 @@ Blocklist.prototype = {
if (!toolkitVersion)
toolkitVersion = gApp.platformVersion;
var blItem = addonEntries[id];
var blItem = this._findMatchingAddonEntry(addonEntries, id);
if (!blItem)
return Ci.nsIBlocklistService.STATE_NOT_BLOCKED;
for (let currentblItem of blItem) {
for (let currentblItem of blItem.versions) {
if (currentblItem.includesItem(version, appVersion, toolkitVersion))
return currentblItem.severity >= gBlocklistLevel ? Ci.nsIBlocklistService.STATE_BLOCKED :
Ci.nsIBlocklistService.STATE_SOFTBLOCKED;
@ -354,6 +370,19 @@ Blocklist.prototype = {
return Ci.nsIBlocklistService.STATE_NOT_BLOCKED;
},
_findMatchingAddonEntry: function Blocklist_findMatchingAddonEntry(aAddonEntries,
aId) {
for (let entry of aAddonEntries) {
if (entry.id instanceof RegExp) {
if (entry.id.test(aId))
return entry;
} else if (entry.id == aId) {
return entry;
}
}
return null;
},
/* See nsIBlocklistService */
getAddonBlocklistURL: function Blocklist_getAddonBlocklistURL(id, version, appVersion, toolkitVersion) {
if (!gBlocklistEnabled)
@ -362,7 +391,7 @@ Blocklist.prototype = {
if (!this._addonEntries)
this._loadBlocklist();
let blItem = this._addonEntries[id];
let blItem = this._findMatchingAddonEntry(this._addonEntries, id);
if (!blItem || !blItem.blockID)
return null;
@ -516,8 +545,8 @@ Blocklist.prototype = {
var oldAddonEntries = this._addonEntries;
var oldPluginEntries = this._pluginEntries;
this._addonEntries = { };
this._pluginEntries = { };
this._addonEntries = [];
this._pluginEntries = [];
this._loadBlocklistFromFile(FileUtils.getFile(KEY_PROFILEDIR,
[FILE_BLOCKLIST]));
@ -551,8 +580,8 @@ Blocklist.prototype = {
* load it or does nothing if neither exist.
*/
_loadBlocklist: function Blocklist_loadBlocklist() {
this._addonEntries = { };
this._pluginEntries = { };
this._addonEntries = [];
this._pluginEntries = [];
var profFile = FileUtils.getFile(KEY_PROFILEDIR, [FILE_BLOCKLIST]);
if (profFile.exists()) {
this._loadBlocklistFromFile(profFile);
@ -606,7 +635,7 @@ Blocklist.prototype = {
# <versionRange minVersion="1.5" maxVersion="1.5.*"/>
# </targetApplication>
# </versionRange>
# <emItem id="item_5@domain"/>
# <emItem id="/@badperson\.com$/"/>
# </emItems>
# <pluginItems>
# <pluginItem blockID="i4">
@ -688,23 +717,35 @@ Blocklist.prototype = {
if (!matchesOSABI(blocklistElement))
return;
let blockEntry = {
id: null,
versions: [],
blockID: null
};
var versionNodes = blocklistElement.childNodes;
var id = blocklistElement.getAttribute("id");
result[id] = [];
// Add-on IDs cannot contain '/', so an ID starting with '/' must be a regex
if (id.startsWith("/"))
id = parseRegExp(id);
blockEntry.id = id;
for (var x = 0; x < versionNodes.length; ++x) {
var versionRangeElement = versionNodes.item(x);
if (!(versionRangeElement instanceof Ci.nsIDOMElement) ||
versionRangeElement.localName != "versionRange")
continue;
result[id].push(new BlocklistItemData(versionRangeElement));
blockEntry.versions.push(new BlocklistItemData(versionRangeElement));
}
// if only the extension ID is specified block all versions of the
// extension for the current application.
if (result[id].length == 0)
result[id].push(new BlocklistItemData(null));
if (blockEntry.versions.length == 0)
blockEntry.versions.push(new BlocklistItemData(null));
result[id].blockID = blocklistElement.getAttribute("blockID");
blockEntry.blockID = blocklistElement.getAttribute("blockID");
result.push(blockEntry);
},
_handlePluginItemNode: function Blocklist_handlePluginItemNode(blocklistElement, result) {

View File

@ -0,0 +1,19 @@
<?xml version="1.0"?>
<RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:em="http://www.mozilla.org/2004/em-rdf#">
<Description about="urn:mozilla:install-manifest">
<em:id>regexpblock@tests.mozilla.org</em:id>
<em:version>1.0</em:version>
<em:name>RegExp-blocked add-on</em:name>
<em:updateURL>http://localhost:4444/data/addon_update1.rdf</em:updateURL>
<em:targetApplication>
<Description>
<em:id>xpcshell@tests.mozilla.org</em:id>
<em:minVersion>1</em:minVersion>
<em:maxVersion>3</em:maxVersion>
</Description>
</em:targetApplication>
</Description>
</RDF>

View File

@ -0,0 +1,19 @@
<?xml version="1.0"?>
<RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:em="http://www.mozilla.org/2004/em-rdf#">
<Description about="urn:mozilla:install-manifest">
<em:id>regexpblock@tests.mozilla.org</em:id>
<em:version>2.0</em:version>
<em:name>RegExp-blocked add-on</em:name>
<em:updateURL>http://localhost:4444/data/addon_update2.rdf</em:updateURL>
<em:targetApplication>
<Description>
<em:id>xpcshell@tests.mozilla.org</em:id>
<em:minVersion>1</em:minVersion>
<em:maxVersion>3</em:maxVersion>
</Description>
</em:targetApplication>
</Description>
</RDF>

View File

@ -0,0 +1,19 @@
<?xml version="1.0"?>
<RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:em="http://www.mozilla.org/2004/em-rdf#">
<Description about="urn:mozilla:install-manifest">
<em:id>regexpblock@tests.mozilla.org</em:id>
<em:version>3.0</em:version>
<em:name>RegExp-blocked add-on</em:name>
<em:updateURL>http://localhost:4444/data/addon_update3.rdf</em:updateURL>
<em:targetApplication>
<Description>
<em:id>xpcshell@tests.mozilla.org</em:id>
<em:minVersion>1</em:minVersion>
<em:maxVersion>3</em:maxVersion>
</Description>
</em:targetApplication>
</Description>
</RDF>

View File

@ -20,5 +20,12 @@
<emItem id="hardblock@tests.mozilla.org">
<versionRange minVersion="2" maxVersion="3"/>
</emItem>
<!-- Two RegExp matches, so test flags work - first shouldn't match. -->
<emItem id="/^RegExp/">
<versionRange severity="1" minVersion="2" maxVersion="3"/>
</emItem>
<emItem id="/^RegExp/i">
<versionRange severity="2" minVersion="2" maxVersion="3"/>
</emItem>
</emItems>
</blocklist>

View File

@ -121,4 +121,24 @@
</RDF:Seq>
</em:updates>
</RDF:Description>
<RDF:Description about="urn:mozilla:extension:regexpblock@tests.mozilla.org">
<em:updates>
<RDF:Seq>
<RDF:li>
<RDF:Description>
<em:version>2</em:version>
<em:targetApplication>
<RDF:Description>
<em:id>toolkit@mozilla.org</em:id>
<em:minVersion>0</em:minVersion>
<em:maxVersion>*</em:maxVersion>
<em:updateLink>http://localhost:4444/addons/blocklist_regexp1_2.xpi</em:updateLink>
</RDF:Description>
</em:targetApplication>
</RDF:Description>
</RDF:li>
</RDF:Seq>
</em:updates>
</RDF:Description>
</RDF:RDF>

View File

@ -121,4 +121,24 @@
</RDF:Seq>
</em:updates>
</RDF:Description>
<RDF:Description about="urn:mozilla:extension:regexpblock@tests.mozilla.org">
<em:updates>
<RDF:Seq>
<RDF:li>
<RDF:Description>
<em:version>3</em:version>
<em:targetApplication>
<RDF:Description>
<em:id>toolkit@mozilla.org</em:id>
<em:minVersion>0</em:minVersion>
<em:maxVersion>*</em:maxVersion>
<em:updateLink>http://localhost:4444/addons/blocklist_regexp1_3.xpi</em:updateLink>
</RDF:Description>
</em:targetApplication>
</RDF:Description>
</RDF:li>
</RDF:Seq>
</em:updates>
</RDF:Description>
</RDF:RDF>

View File

@ -121,4 +121,24 @@
</RDF:Seq>
</em:updates>
</RDF:Description>
<RDF:Description about="urn:mozilla:extension:regexpblock@tests.mozilla.org">
<em:updates>
<RDF:Seq>
<RDF:li>
<RDF:Description>
<em:version>4</em:version>
<em:targetApplication>
<RDF:Description>
<em:id>toolkit@mozilla.org</em:id>
<em:minVersion>0</em:minVersion>
<em:maxVersion>*</em:maxVersion>
<em:updateLink>http://localhost:4444/addons/blocklist_regexp1_1.xpi</em:updateLink>
</RDF:Description>
</em:targetApplication>
</RDF:Description>
</RDF:li>
</RDF:Seq>
</em:updates>
</RDF:Description>
</RDF:RDF>

View File

@ -44,5 +44,19 @@
</targetApplication>
</versionRange>
</emItem>
<emItem id="/^RegExp/">
<versionRange severity="1">
<targetApplication id="xpcshell@tests.mozilla.org">
<versionRange minVersion="2" maxVersion="2.*"/>
</targetApplication>
</versionRange>
</emItem>
<emItem id="/^RegExp/i">
<versionRange>
<targetApplication id="xpcshell@tests.mozilla.org">
<versionRange minVersion="2" maxVersion="2.*"/>
</targetApplication>
</versionRange>
</emItem>
</emItems>
</blocklist>

View File

@ -18,5 +18,9 @@
<versionRange severity="1"/>
</emItem>
<emItem id="hardblock@tests.mozilla.org"/>
<emItem id="/^RegExp/">
<versionRange severity="1"/>
</emItem>
<emItem id="/^RegExp/i"/>
</emItems>
</blocklist>

View File

@ -20,5 +20,8 @@
<emItem id="hardblock@tests.mozilla.org">
<versionRange minVersion="1" maxVersion="2"/>
</emItem>
<emItem id="/^RegExp/i">
<versionRange minVersion="1" maxVersion="2"/>
</emItem>
</emItems>
</blocklist>

View File

@ -0,0 +1,20 @@
<?xml version="1.0" encoding="UTF-8"?>
<blocklist xmlns="http://www.mozilla.org/2006/addons-blocklist">
<emItems>
<emItem id="/block1/">
<versionRange severity="1">
<targetApplication id="xpcshell@tests.mozilla.org">
<versionRange minVersion="1" maxVersion="2.*"/>
</targetApplication>
</versionRange>
</emItem>
<emItem id="/block1/">
<versionRange severity="2">
<targetApplication id="xpcshell@tests.mozilla.org">
<versionRange minVersion="1" maxVersion="2.*"/>
</targetApplication>
</versionRange>
</emItem>
</emItems>
</blocklist>

View File

@ -0,0 +1,123 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/
*/
// Checks that blocklist entries using RegExp work as expected. This only covers
// behavior specific to RegExp entries - general behavior is already tested
// in test_blocklistchange.js.
const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
const URI_EXTENSION_BLOCKLIST_DIALOG = "chrome://mozapps/content/extensions/blocklist.xul";
Cu.import("resource://testing-common/httpd.js");
var testserver;
const profileDir = gProfD.clone();
profileDir.append("extensions");
// Don't need the full interface, attempts to call other methods will just
// throw which is just fine
var WindowWatcher = {
openWindow: function(parent, url, name, features, arguments) {
// Should be called to list the newly blocklisted items
do_check_eq(url, URI_EXTENSION_BLOCKLIST_DIALOG);
// Simulate auto-disabling any softblocks
var list = arguments.wrappedJSObject.list;
list.forEach(function(aItem) {
if (!aItem.blocked)
aItem.disable = true;
});
//run the code after the blocklist is closed
Services.obs.notifyObservers(null, "addon-blocklist-closed", null);
},
QueryInterface: function(iid) {
if (iid.equals(Ci.nsIWindowWatcher)
|| iid.equals(Ci.nsISupports))
return this;
throw Cr.NS_ERROR_NO_INTERFACE;
}
};
var WindowWatcherFactory = {
createInstance: function createInstance(outer, iid) {
if (outer != null)
throw Cr.NS_ERROR_NO_AGGREGATION;
return WindowWatcher.QueryInterface(iid);
}
};
var registrar = Components.manager.QueryInterface(Ci.nsIComponentRegistrar);
registrar.registerFactory(Components.ID("{1dfeb90a-2193-45d5-9cb8-864928b2af55}"),
"Fake Window Watcher",
"@mozilla.org/embedcomp/window-watcher;1",
WindowWatcherFactory);
function load_blocklist(aFile, aCallback) {
Services.obs.addObserver(function() {
Services.obs.removeObserver(arguments.callee, "blocklist-updated");
do_execute_soon(aCallback);
}, "blocklist-updated", false);
Services.prefs.setCharPref("extensions.blocklist.url", "http://localhost:4444/data/" + aFile);
var blocklist = Cc["@mozilla.org/extensions/blocklist;1"].
getService(Ci.nsITimerCallback);
blocklist.notify(null);
}
function end_test() {
testserver.stop(do_test_finished);
}
function run_test() {
testserver = new HttpServer();
testserver.registerDirectory("/data/", do_get_file("data"));
testserver.start(4444);
do_test_pending();
createAppInfo("xpcshell@tests.mozilla.org", "XPCShell", "1", "1");
writeInstallRDFForExtension({
id: "block1@tests.mozilla.org",
version: "1.0",
name: "RegExp blocked add-on",
targetApplications: [{
id: "xpcshell@tests.mozilla.org",
minVersion: "1",
maxVersion: "3"
}]
}, profileDir);
startupManager();
AddonManager.getAddonsByIDs(["block1@tests.mozilla.org"], function([a1]) {
do_check_eq(a1.blocklistState, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
run_test_1();
});
}
function run_test_1() {
load_blocklist("test_blocklist_regexp_1.xml", function() {
restartManager();
AddonManager.getAddonsByIDs(["block1@tests.mozilla.org"], function([a1]) {
// Blocklist contains two entries that will match this addon - ensure
// that the first one is applied.
do_check_neq(a1, null);
do_check_eq(a1.blocklistState, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
end_test();
});
});
}

View File

@ -273,12 +273,49 @@ var hardblock_3 = {
}]
};
var regexpblock_1 = {
id: "regexpblock@tests.mozilla.org",
version: "1.0",
name: "RegExp-blocked add-on",
updateURL: "http://localhost:4444/data/addon_update1.rdf",
targetApplications: [{
id: "xpcshell@tests.mozilla.org",
minVersion: "1",
maxVersion: "3"
}]
};
var regexpblock_2 = {
id: "regexpblock@tests.mozilla.org",
version: "2.0",
name: "RegExp-blocked add-on",
updateURL: "http://localhost:4444/data/addon_update2.rdf",
targetApplications: [{
id: "xpcshell@tests.mozilla.org",
minVersion: "1",
maxVersion: "3"
}]
};
var regexpblock_3 = {
id: "regexpblock@tests.mozilla.org",
version: "3.0",
name: "RegExp-blocked add-on",
updateURL: "http://localhost:4444/data/addon_update3.rdf",
targetApplications: [{
id: "xpcshell@tests.mozilla.org",
minVersion: "1",
maxVersion: "3"
}]
};
const ADDON_IDS = ["softblock1@tests.mozilla.org",
"softblock2@tests.mozilla.org",
"softblock3@tests.mozilla.org",
"softblock4@tests.mozilla.org",
"softblock5@tests.mozilla.org",
"hardblock@tests.mozilla.org"];
"hardblock@tests.mozilla.org",
"regexpblock@tests.mozilla.org"];
// Don't need the full interface, attempts to call other methods will just
// throw which is just fine
@ -428,42 +465,46 @@ function manual_update(aVersion, aCallback) {
AddonManager.getInstallForURL("http://localhost:4444/addons/blocklist_hard1_" + aVersion + ".xpi",
function(aInstall) {
installs.push(aInstall);
AddonManager.getInstallForURL("http://localhost:4444/addons/blocklist_regexp1_" + aVersion + ".xpi",
function(aInstall) {
installs.push(aInstall);
Services.obs.addObserver(function(aSubject, aTopic, aData) {
Services.obs.removeObserver(arguments.callee, "addon-install-blocked");
Services.obs.addObserver(function(aSubject, aTopic, aData) {
Services.obs.removeObserver(arguments.callee, "addon-install-blocked");
aSubject.QueryInterface(Ci.amIWebInstallInfo);
aSubject.QueryInterface(Ci.amIWebInstallInfo);
var installCount = aSubject.installs.length;
var installCount = aSubject.installs.length;
var listener = {
installComplete: function() {
installCount--;
if (installCount)
return;
var listener = {
installComplete: function() {
installCount--;
if (installCount)
return;
do_execute_soon(aCallback);
},
do_execute_soon(aCallback);
},
onDownloadCancelled: function(aInstall) {
this.installComplete();
},
onDownloadCancelled: function(aInstall) {
this.installComplete();
},
onInstallEnded: function(aInstall) {
this.installComplete();
}
};
onInstallEnded: function(aInstall) {
this.installComplete();
}
};
aSubject.installs.forEach(function(aInstall) {
aInstall.addListener(listener);
});
aSubject.installs.forEach(function(aInstall) {
aInstall.addListener(listener);
});
aSubject.install();
}, "addon-install-blocked", false);
aSubject.install();
}, "addon-install-blocked", false);
AddonManager.installAddonsFromWebpage("application/x-xpinstall", null,
NetUtil.newURI("http://localhost:4444/"),
installs);
AddonManager.installAddonsFromWebpage("application/x-xpinstall", null,
NetUtil.newURI("http://localhost:4444/"),
installs);
}, "application/x-xpinstall");
}, "application/x-xpinstall");
}, "application/x-xpinstall");
}, "application/x-xpinstall");
@ -480,6 +521,7 @@ function check_addon(aAddon, aExpectedVersion, aExpectedUserDisabled,
do_check_neq(aAddon, null);
do_check_eq(aAddon.version, aExpectedVersion);
do_check_eq(aAddon.blocklistState, aExpectedState);
do_check_eq(aAddon.userDisabled, aExpectedUserDisabled);
do_check_eq(aAddon.softDisabled, aExpectedSoftDisabled);
if (aAddon.softDisabled)
@ -499,7 +541,6 @@ function check_addon(aAddon, aExpectedVersion, aExpectedUserDisabled,
do_check_true(hasFlag(aAddon.permissions, AddonManager.PERM_CAN_DISABLE));
}
do_check_eq(aAddon.appDisabled, aExpectedState == Ci.nsIBlocklistService.STATE_BLOCKED);
do_check_eq(aAddon.blocklistState, aExpectedState);
let willBeActive = aAddon.isActive;
if (hasFlag(aAddon.pendingOperations, AddonManager.PENDING_DISABLE))
@ -532,9 +573,10 @@ function run_test() {
writeInstallRDFForExtension(softblock4_1, profileDir);
writeInstallRDFForExtension(softblock5_1, profileDir);
writeInstallRDFForExtension(hardblock_1, profileDir);
writeInstallRDFForExtension(regexpblock_1, profileDir);
startupManager();
AddonManager.getAddonsByIDs(ADDON_IDS, function([s1, s2, s3, s4, s5, h]) {
AddonManager.getAddonsByIDs(ADDON_IDS, function([s1, s2, s3, s4, s5, h, r]) {
s4.userDisabled = true;
s5.userDisabled = false;
restartManager();
@ -554,7 +596,7 @@ function run_app_update_test() {
load_blocklist("app_update.xml", function() {
restartManager();
AddonManager.getAddonsByIDs(ADDON_IDS, function([s1, s2, s3, s4, s5, h]) {
AddonManager.getAddonsByIDs(ADDON_IDS, function([s1, s2, s3, s4, s5, h, r]) {
check_addon(s1, "1.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
check_addon(s2, "1.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
@ -562,11 +604,12 @@ function run_app_update_test() {
check_addon(s4, "1.0", true, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
check_addon(s5, "1.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
check_addon(h, "1.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
check_addon(r, "1.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
do_check_eq(Services.prefs.getCharPref("general.skins.selectedSkin"), "test/1.0");
restartManager("2");
AddonManager.getAddonsByIDs(ADDON_IDS, function([s1, s2, s3, s4, s5, h]) {
AddonManager.getAddonsByIDs(ADDON_IDS, function([s1, s2, s3, s4, s5, h, r]) {
check_addon(s1, "1.0", true, true, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
check_addon(s2, "1.0", true, true, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
@ -574,6 +617,7 @@ function run_app_update_test() {
check_addon(s4, "1.0", true, false, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
check_addon(s5, "1.0", true, false, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
check_addon(h, "1.0", false, false, Ci.nsIBlocklistService.STATE_BLOCKED);
check_addon(r, "1.0", false, false, Ci.nsIBlocklistService.STATE_BLOCKED);
do_check_eq(Services.prefs.getCharPref("general.skins.selectedSkin"), "classic/1.0");
s2.userDisabled = false;
@ -585,7 +629,7 @@ function run_app_update_test() {
restartManager("2.5");
AddonManager.getAddonsByIDs(ADDON_IDS, function([s1, s2, s3, s4, s5, h]) {
AddonManager.getAddonsByIDs(ADDON_IDS, function([s1, s2, s3, s4, s5, h, r]) {
check_addon(s1, "1.0", true, true, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
check_addon(s2, "1.0", true, false, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
@ -593,11 +637,12 @@ function run_app_update_test() {
check_addon(s4, "1.0", true, false, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
check_addon(s5, "1.0", true, false, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
check_addon(h, "1.0", false, false, Ci.nsIBlocklistService.STATE_BLOCKED);
check_addon(r, "1.0", false, false, Ci.nsIBlocklistService.STATE_BLOCKED);
do_check_eq(Services.prefs.getCharPref("general.skins.selectedSkin"), "classic/1.0");
restartManager("1");
AddonManager.getAddonsByIDs(ADDON_IDS, function([s1, s2, s3, s4, s5, h]) {
AddonManager.getAddonsByIDs(ADDON_IDS, function([s1, s2, s3, s4, s5, h, r]) {
check_addon(s1, "1.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
check_addon(s2, "1.0", true, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
@ -605,6 +650,7 @@ function run_app_update_test() {
check_addon(s4, "1.0", true, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
check_addon(s5, "1.0", true, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
check_addon(h, "1.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
check_addon(r, "1.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
do_check_eq(Services.prefs.getCharPref("general.skins.selectedSkin"), "classic/1.0");
s1.userDisabled = false;
@ -625,7 +671,7 @@ function run_app_update_schema_test() {
dump(arguments.callee.name + "\n");
restartManager();
AddonManager.getAddonsByIDs(ADDON_IDS, function([s1, s2, s3, s4, s5, h]) {
AddonManager.getAddonsByIDs(ADDON_IDS, function([s1, s2, s3, s4, s5, h, r]) {
check_addon(s1, "1.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
check_addon(s2, "1.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
@ -633,6 +679,7 @@ function run_app_update_schema_test() {
check_addon(s4, "1.0", true, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
check_addon(s5, "1.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
check_addon(h, "1.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
check_addon(r, "1.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
do_check_eq(Services.prefs.getCharPref("general.skins.selectedSkin"), "test/1.0");
shutdownManager();
@ -644,7 +691,7 @@ function run_app_update_schema_test() {
gAppInfo.version = "2";
startupManager(true);
AddonManager.getAddonsByIDs(ADDON_IDS, function([s1, s2, s3, s4, s5, h]) {
AddonManager.getAddonsByIDs(ADDON_IDS, function([s1, s2, s3, s4, s5, h, r]) {
check_addon(s1, "1.0", true, true, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
check_addon(s2, "1.0", true, true, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
@ -652,6 +699,7 @@ function run_app_update_schema_test() {
check_addon(s4, "1.0", true, false, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
check_addon(s5, "1.0", true, false, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
check_addon(h, "1.0", false, false, Ci.nsIBlocklistService.STATE_BLOCKED);
check_addon(r, "1.0", false, false, Ci.nsIBlocklistService.STATE_BLOCKED);
do_check_eq(Services.prefs.getCharPref("general.skins.selectedSkin"), "classic/1.0");
s2.userDisabled = false;
@ -670,7 +718,7 @@ function run_app_update_schema_test() {
gAppInfo.version = "2.5";
startupManager(true);
AddonManager.getAddonsByIDs(ADDON_IDS, function([s1, s2, s3, s4, s5, h]) {
AddonManager.getAddonsByIDs(ADDON_IDS, function([s1, s2, s3, s4, s5, h, r]) {
check_addon(s1, "1.0", true, true, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
check_addon(s2, "1.0", true, false, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
@ -678,6 +726,7 @@ function run_app_update_schema_test() {
check_addon(s4, "1.0", true, false, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
check_addon(s5, "1.0", true, false, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
check_addon(h, "1.0", false, false, Ci.nsIBlocklistService.STATE_BLOCKED);
check_addon(r, "1.0", false, false, Ci.nsIBlocklistService.STATE_BLOCKED);
do_check_eq(Services.prefs.getCharPref("general.skins.selectedSkin"), "classic/1.0");
shutdownManager();
@ -688,7 +737,7 @@ function run_app_update_schema_test() {
db.close();
startupManager(false);
AddonManager.getAddonsByIDs(ADDON_IDS, function([s1, s2, s3, s4, s5, h]) {
AddonManager.getAddonsByIDs(ADDON_IDS, function([s1, s2, s3, s4, s5, h, r]) {
check_addon(s1, "1.0", true, true, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
check_addon(s2, "1.0", true, false, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
@ -696,6 +745,7 @@ function run_app_update_schema_test() {
check_addon(s4, "1.0", true, false, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
check_addon(s5, "1.0", true, false, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
check_addon(h, "1.0", false, false, Ci.nsIBlocklistService.STATE_BLOCKED);
check_addon(r, "1.0", false, false, Ci.nsIBlocklistService.STATE_BLOCKED);
do_check_eq(Services.prefs.getCharPref("general.skins.selectedSkin"), "classic/1.0");
shutdownManager();
@ -707,7 +757,7 @@ function run_app_update_schema_test() {
gAppInfo.version = "1";
startupManager(true);
AddonManager.getAddonsByIDs(ADDON_IDS, function([s1, s2, s3, s4, s5, h]) {
AddonManager.getAddonsByIDs(ADDON_IDS, function([s1, s2, s3, s4, s5, h, r]) {
check_addon(s1, "1.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
check_addon(s2, "1.0", true, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
@ -715,6 +765,7 @@ function run_app_update_schema_test() {
check_addon(s4, "1.0", true, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
check_addon(s5, "1.0", true, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
check_addon(h, "1.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
check_addon(r, "1.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
do_check_eq(Services.prefs.getCharPref("general.skins.selectedSkin"), "classic/1.0");
s1.userDisabled = false;
@ -735,7 +786,7 @@ function run_blocklist_update_test() {
load_blocklist("blocklist_update1.xml", function() {
restartManager();
AddonManager.getAddonsByIDs(ADDON_IDS, function([s1, s2, s3, s4, s5, h]) {
AddonManager.getAddonsByIDs(ADDON_IDS, function([s1, s2, s3, s4, s5, h, r]) {
check_addon(s1, "1.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
check_addon(s2, "1.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
@ -743,12 +794,13 @@ function run_blocklist_update_test() {
check_addon(s4, "1.0", true, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
check_addon(s5, "1.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
check_addon(h, "1.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
check_addon(r, "1.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
do_check_eq(Services.prefs.getCharPref("general.skins.selectedSkin"), "test/1.0");
load_blocklist("blocklist_update2.xml", function() {
restartManager();
AddonManager.getAddonsByIDs(ADDON_IDS, function([s1, s2, s3, s4, s5, h]) {
AddonManager.getAddonsByIDs(ADDON_IDS, function([s1, s2, s3, s4, s5, h, r]) {
check_addon(s1, "1.0", true, true, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
check_addon(s2, "1.0", true, true, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
@ -756,6 +808,7 @@ function run_blocklist_update_test() {
check_addon(s4, "1.0", true, false, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
check_addon(s5, "1.0", true, false, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
check_addon(h, "1.0", false, false, Ci.nsIBlocklistService.STATE_BLOCKED);
check_addon(r, "1.0", false, false, Ci.nsIBlocklistService.STATE_BLOCKED);
do_check_eq(Services.prefs.getCharPref("general.skins.selectedSkin"), "classic/1.0");
s2.userDisabled = false;
@ -768,7 +821,7 @@ function run_blocklist_update_test() {
load_blocklist("blocklist_update2.xml", function() {
restartManager();
AddonManager.getAddonsByIDs(ADDON_IDS, function([s1, s2, s3, s4, s5, h]) {
AddonManager.getAddonsByIDs(ADDON_IDS, function([s1, s2, s3, s4, s5, h, r]) {
check_addon(s1, "1.0", true, true, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
check_addon(s2, "1.0", true, false, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
@ -776,12 +829,13 @@ function run_blocklist_update_test() {
check_addon(s4, "1.0", true, false, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
check_addon(s5, "1.0", true, false, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
check_addon(h, "1.0", false, false, Ci.nsIBlocklistService.STATE_BLOCKED);
check_addon(r, "1.0", false, false, Ci.nsIBlocklistService.STATE_BLOCKED);
do_check_eq(Services.prefs.getCharPref("general.skins.selectedSkin"), "classic/1.0");
load_blocklist("blocklist_update1.xml", function() {
restartManager();
AddonManager.getAddonsByIDs(ADDON_IDS, function([s1, s2, s3, s4, s5, h]) {
AddonManager.getAddonsByIDs(ADDON_IDS, function([s1, s2, s3, s4, s5, h, r]) {
check_addon(s1, "1.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
check_addon(s2, "1.0", true, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
@ -789,6 +843,7 @@ function run_blocklist_update_test() {
check_addon(s4, "1.0", true, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
check_addon(s5, "1.0", true, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
check_addon(h, "1.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
check_addon(r, "1.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
do_check_eq(Services.prefs.getCharPref("general.skins.selectedSkin"), "classic/1.0");
s1.userDisabled = false;
@ -812,7 +867,7 @@ function run_addon_change_test() {
load_blocklist("addon_change.xml", function() {
restartManager();
AddonManager.getAddonsByIDs(ADDON_IDS, function([s1, s2, s3, s4, s5, h]) {
AddonManager.getAddonsByIDs(ADDON_IDS, function([s1, s2, s3, s4, s5, h, r]) {
check_addon(s1, "1.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
check_addon(s2, "1.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
@ -820,6 +875,7 @@ function run_addon_change_test() {
check_addon(s4, "1.0", true, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
check_addon(s5, "1.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
check_addon(h, "1.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
check_addon(r, "1.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
do_check_eq(Services.prefs.getCharPref("general.skins.selectedSkin"), "test/1.0");
shutdownManager();
@ -836,10 +892,12 @@ function run_addon_change_test() {
setExtensionModifiedTime(getFileForAddon(profileDir, softblock5_2.id), Date.now() + 10000);
writeInstallRDFForExtension(hardblock_2, profileDir);
setExtensionModifiedTime(getFileForAddon(profileDir, hardblock_2.id), Date.now() + 10000);
writeInstallRDFForExtension(regexpblock_2, profileDir);
setExtensionModifiedTime(getFileForAddon(profileDir, regexpblock_2.id), Date.now() + 10000);
startupManager(false);
AddonManager.getAddonsByIDs(ADDON_IDS, function([s1, s2, s3, s4, s5, h]) {
AddonManager.getAddonsByIDs(ADDON_IDS, function([s1, s2, s3, s4, s5, h, r]) {
check_addon(s1, "2.0", true, true, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
check_addon(s2, "2.0", true, true, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
@ -847,6 +905,7 @@ function run_addon_change_test() {
check_addon(s4, "2.0", true, false, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
check_addon(s5, "2.0", true, false, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
check_addon(h, "2.0", false, false, Ci.nsIBlocklistService.STATE_BLOCKED);
check_addon(r, "2.0", false, false, Ci.nsIBlocklistService.STATE_BLOCKED);
do_check_eq(Services.prefs.getCharPref("general.skins.selectedSkin"), "classic/1.0");
s2.userDisabled = false;
@ -870,10 +929,12 @@ function run_addon_change_test() {
setExtensionModifiedTime(getFileForAddon(profileDir, softblock5_3.id), Date.now() + 20000);
writeInstallRDFForExtension(hardblock_3, profileDir);
setExtensionModifiedTime(getFileForAddon(profileDir, hardblock_3.id), Date.now() + 20000);
writeInstallRDFForExtension(regexpblock_3, profileDir);
setExtensionModifiedTime(getFileForAddon(profileDir, regexpblock_3.id), Date.now() + 20000);
startupManager(false);
AddonManager.getAddonsByIDs(ADDON_IDS, function([s1, s2, s3, s4, s5, h]) {
AddonManager.getAddonsByIDs(ADDON_IDS, function([s1, s2, s3, s4, s5, h, r]) {
check_addon(s1, "3.0", true, true, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
check_addon(s2, "3.0", true, false, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
@ -881,6 +942,7 @@ function run_addon_change_test() {
check_addon(s4, "3.0", true, false, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
check_addon(s5, "3.0", true, false, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
check_addon(h, "3.0", false, false, Ci.nsIBlocklistService.STATE_BLOCKED);
check_addon(r, "3.0", false, false, Ci.nsIBlocklistService.STATE_BLOCKED);
do_check_eq(Services.prefs.getCharPref("general.skins.selectedSkin"), "classic/1.0");
shutdownManager();
@ -897,10 +959,12 @@ function run_addon_change_test() {
setExtensionModifiedTime(getFileForAddon(profileDir, softblock5_1.id), Date.now() + 30000);
writeInstallRDFForExtension(hardblock_1, profileDir);
setExtensionModifiedTime(getFileForAddon(profileDir, hardblock_1.id), Date.now() + 30000);
writeInstallRDFForExtension(regexpblock_1, profileDir);
setExtensionModifiedTime(getFileForAddon(profileDir, regexpblock_1.id), Date.now() + 30000);
startupManager(false);
AddonManager.getAddonsByIDs(ADDON_IDS, function([s1, s2, s3, s4, s5, h]) {
AddonManager.getAddonsByIDs(ADDON_IDS, function([s1, s2, s3, s4, s5, h, r]) {
check_addon(s1, "1.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
check_addon(s2, "1.0", true, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
@ -908,6 +972,7 @@ function run_addon_change_test() {
check_addon(s4, "1.0", true, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
check_addon(s5, "1.0", true, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
check_addon(h, "1.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
check_addon(r, "1.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
do_check_eq(Services.prefs.getCharPref("general.skins.selectedSkin"), "classic/1.0");
s1.userDisabled = false;
@ -933,6 +998,7 @@ function run_addon_change_2_test() {
getFileForAddon(profileDir, softblock4_1.id).remove(true);
getFileForAddon(profileDir, softblock5_1.id).remove(true);
getFileForAddon(profileDir, hardblock_1.id).remove(true);
getFileForAddon(profileDir, regexpblock_1.id).remove(true);
startupManager(false);
shutdownManager();
@ -943,15 +1009,17 @@ function run_addon_change_2_test() {
writeInstallRDFForExtension(softblock4_2, profileDir);
writeInstallRDFForExtension(softblock5_2, profileDir);
writeInstallRDFForExtension(hardblock_2, profileDir);
writeInstallRDFForExtension(regexpblock_2, profileDir);
startupManager(false);
AddonManager.getAddonsByIDs(ADDON_IDS, function([s1, s2, s3, s4, s5, h]) {
AddonManager.getAddonsByIDs(ADDON_IDS, function([s1, s2, s3, s4, s5, h, r]) {
check_addon(s1, "2.0", true, true, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
check_addon(s2, "2.0", true, true, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
check_addon(s3, "2.0", true, true, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
check_addon(h, "2.0", false, false, Ci.nsIBlocklistService.STATE_BLOCKED);
check_addon(r, "2.0", false, false, Ci.nsIBlocklistService.STATE_BLOCKED);
s2.userDisabled = false;
s2.userDisabled = true;
@ -974,15 +1042,18 @@ function run_addon_change_2_test() {
setExtensionModifiedTime(getFileForAddon(profileDir, softblock5_3.id), Date.now() + 10000);
writeInstallRDFForExtension(hardblock_3, profileDir);
setExtensionModifiedTime(getFileForAddon(profileDir, hardblock_3.id), Date.now() + 10000);
writeInstallRDFForExtension(regexpblock_3, profileDir);
setExtensionModifiedTime(getFileForAddon(profileDir, regexpblock_3.id), Date.now() + 10000);
startupManager(false);
AddonManager.getAddonsByIDs(ADDON_IDS, function([s1, s2, s3, s4, s5, h]) {
AddonManager.getAddonsByIDs(ADDON_IDS, function([s1, s2, s3, s4, s5, h, r]) {
check_addon(s1, "3.0", true, true, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
check_addon(s2, "3.0", true, false, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
check_addon(s3, "3.0", false, false, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
check_addon(h, "3.0", false, false, Ci.nsIBlocklistService.STATE_BLOCKED);
check_addon(r, "3.0", false, false, Ci.nsIBlocklistService.STATE_BLOCKED);
shutdownManager();
@ -998,15 +1069,18 @@ function run_addon_change_2_test() {
setExtensionModifiedTime(getFileForAddon(profileDir, softblock5_1.id), Date.now() + 20000);
writeInstallRDFForExtension(hardblock_1, profileDir);
setExtensionModifiedTime(getFileForAddon(profileDir, hardblock_1.id), Date.now() + 20000);
writeInstallRDFForExtension(regexpblock_1, profileDir);
setExtensionModifiedTime(getFileForAddon(profileDir, regexpblock_1.id), Date.now() + 20000);
startupManager(false);
AddonManager.getAddonsByIDs(ADDON_IDS, function([s1, s2, s3, s4, s5, h]) {
AddonManager.getAddonsByIDs(ADDON_IDS, function([s1, s2, s3, s4, s5, h, r]) {
check_addon(s1, "1.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
check_addon(s2, "1.0", true, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
check_addon(s3, "1.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
check_addon(h, "1.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
check_addon(r, "1.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
s1.userDisabled = false;
s2.userDisabled = false;
@ -1024,7 +1098,7 @@ function run_background_update_test() {
dump(arguments.callee.name + "\n");
restartManager();
AddonManager.getAddonsByIDs(ADDON_IDS, function([s1, s2, s3, s4, s5, h]) {
AddonManager.getAddonsByIDs(ADDON_IDS, function([s1, s2, s3, s4, s5, h, r]) {
check_addon(s1, "1.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
check_addon(s2, "1.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
@ -1032,11 +1106,12 @@ function run_background_update_test() {
check_addon(s4, "1.0", true, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
check_addon(s5, "1.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
check_addon(h, "1.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
check_addon(r, "1.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
background_update(function() {
restartManager();
AddonManager.getAddonsByIDs(ADDON_IDS, function([s1, s2, s3, s4, s5, h]) {
AddonManager.getAddonsByIDs(ADDON_IDS, function([s1, s2, s3, s4, s5, h, r]) {
check_addon(s1, "1.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
check_addon(s2, "1.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
@ -1044,6 +1119,7 @@ function run_background_update_test() {
check_addon(s4, "1.0", true, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
check_addon(s5, "1.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
check_addon(h, "1.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
check_addon(r, "1.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
run_background_update_2_test();
});
@ -1063,6 +1139,7 @@ function run_background_update_2_test() {
getFileForAddon(profileDir, softblock4_1.id).remove(true);
getFileForAddon(profileDir, softblock5_1.id).remove(true);
getFileForAddon(profileDir, hardblock_1.id).remove(true);
getFileForAddon(profileDir, regexpblock_1.id).remove(true);
startupManager(false);
shutdownManager();
@ -1073,15 +1150,17 @@ function run_background_update_2_test() {
writeInstallRDFForExtension(softblock4_3, profileDir);
writeInstallRDFForExtension(softblock5_3, profileDir);
writeInstallRDFForExtension(hardblock_3, profileDir);
writeInstallRDFForExtension(regexpblock_3, profileDir);
startupManager(false);
AddonManager.getAddonsByIDs(ADDON_IDS, function([s1, s2, s3, s4, s5, h]) {
AddonManager.getAddonsByIDs(ADDON_IDS, function([s1, s2, s3, s4, s5, h, r]) {
check_addon(s1, "3.0", true, true, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
check_addon(s2, "3.0", true, true, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
check_addon(s3, "3.0", true, true, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
check_addon(h, "3.0", false, false, Ci.nsIBlocklistService.STATE_BLOCKED);
check_addon(r, "3.0", false, false, Ci.nsIBlocklistService.STATE_BLOCKED);
s2.userDisabled = false;
s2.userDisabled = true;
@ -1093,12 +1172,13 @@ function run_background_update_2_test() {
background_update(function() {
restartManager();
AddonManager.getAddonsByIDs(ADDON_IDS, function([s1, s2, s3, s4, s5, h]) {
AddonManager.getAddonsByIDs(ADDON_IDS, function([s1, s2, s3, s4, s5, h, r]) {
check_addon(s1, "1.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
check_addon(s2, "1.0", true, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
check_addon(s3, "1.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
check_addon(h, "1.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
check_addon(r, "1.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
s1.userDisabled = false;
s2.userDisabled = false;
@ -1118,7 +1198,7 @@ function run_manual_update_test() {
load_blocklist("manual_update.xml", function() {
restartManager();
AddonManager.getAddonsByIDs(ADDON_IDS, function([s1, s2, s3, s4, s5, h]) {
AddonManager.getAddonsByIDs(ADDON_IDS, function([s1, s2, s3, s4, s5, h, r]) {
check_addon(s1, "1.0", true, true, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
check_addon(s2, "1.0", true, true, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
@ -1126,6 +1206,7 @@ function run_manual_update_test() {
check_addon(s4, "1.0", true, false, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
check_addon(s5, "1.0", true, false, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
check_addon(h, "1.0", false, false, Ci.nsIBlocklistService.STATE_BLOCKED);
check_addon(r, "1.0", false, false, Ci.nsIBlocklistService.STATE_BLOCKED);
s2.userDisabled = false;
s2.userDisabled = true;
@ -1137,7 +1218,7 @@ function run_manual_update_test() {
manual_update("2", function() {
restartManager();
AddonManager.getAddonsByIDs(ADDON_IDS, function([s1, s2, s3, s4, s5, h]) {
AddonManager.getAddonsByIDs(ADDON_IDS, function([s1, s2, s3, s4, s5, h, r]) {
check_addon(s1, "2.0", true, true, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
check_addon(s2, "2.0", true, false, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
@ -1146,11 +1227,12 @@ function run_manual_update_test() {
check_addon(s5, "2.0", false, false, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
// Can't manually update to a hardblocked add-on
check_addon(h, "1.0", false, false, Ci.nsIBlocklistService.STATE_BLOCKED);
check_addon(r, "1.0", false, false, Ci.nsIBlocklistService.STATE_BLOCKED);
manual_update("3", function() {
restartManager();
AddonManager.getAddonsByIDs(ADDON_IDS, function([s1, s2, s3, s4, s5, h]) {
AddonManager.getAddonsByIDs(ADDON_IDS, function([s1, s2, s3, s4, s5, h, r]) {
check_addon(s1, "3.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
check_addon(s2, "3.0", true, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
@ -1158,6 +1240,7 @@ function run_manual_update_test() {
check_addon(s4, "3.0", true, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
check_addon(s5, "3.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
check_addon(h, "3.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
check_addon(r, "3.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
run_manual_update_2_test();
});
@ -1180,6 +1263,7 @@ function run_manual_update_2_test() {
getFileForAddon(profileDir, softblock4_1.id).remove(true);
getFileForAddon(profileDir, softblock5_1.id).remove(true);
getFileForAddon(profileDir, hardblock_1.id).remove(true);
getFileForAddon(profileDir, regexpblock_1.id).remove(true);
startupManager(false);
shutdownManager();
@ -1190,15 +1274,17 @@ function run_manual_update_2_test() {
writeInstallRDFForExtension(softblock4_1, profileDir);
writeInstallRDFForExtension(softblock5_1, profileDir);
writeInstallRDFForExtension(hardblock_1, profileDir);
writeInstallRDFForExtension(regexpblock_1, profileDir);
startupManager(false);
AddonManager.getAddonsByIDs(ADDON_IDS, function([s1, s2, s3, s4, s5, h]) {
AddonManager.getAddonsByIDs(ADDON_IDS, function([s1, s2, s3, s4, s5, h, r]) {
check_addon(s1, "1.0", true, true, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
check_addon(s2, "1.0", true, true, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
check_addon(s3, "1.0", true, true, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
check_addon(h, "1.0", false, false, Ci.nsIBlocklistService.STATE_BLOCKED);
check_addon(r, "1.0", false, false, Ci.nsIBlocklistService.STATE_BLOCKED);
s2.userDisabled = false;
s2.userDisabled = true;
@ -1210,25 +1296,27 @@ function run_manual_update_2_test() {
manual_update("2", function() {
restartManager();
AddonManager.getAddonsByIDs(ADDON_IDS, function([s1, s2, s3, s4, s5, h]) {
AddonManager.getAddonsByIDs(ADDON_IDS, function([s1, s2, s3, s4, s5, h, r]) {
check_addon(s1, "2.0", true, true, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
check_addon(s2, "2.0", true, false, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
check_addon(s3, "2.0", false, false, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
// Can't manually update to a hardblocked add-on
check_addon(h, "1.0", false, false, Ci.nsIBlocklistService.STATE_BLOCKED);
check_addon(r, "1.0", false, false, Ci.nsIBlocklistService.STATE_BLOCKED);
restartManager();
manual_update("3", function() {
restartManager();
AddonManager.getAddonsByIDs(ADDON_IDS, function([s1, s2, s3, s4, s5, h]) {
AddonManager.getAddonsByIDs(ADDON_IDS, function([s1, s2, s3, s4, s5, h, r]) {
check_addon(s1, "3.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
check_addon(s2, "3.0", true, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
check_addon(s3, "3.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
check_addon(h, "3.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
check_addon(r, "3.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
s1.userDisabled = false;
s2.userDisabled = false;
@ -1252,6 +1340,7 @@ function run_local_install_test() {
getFileForAddon(profileDir, softblock4_1.id).remove(true);
getFileForAddon(profileDir, softblock5_1.id).remove(true);
getFileForAddon(profileDir, hardblock_1.id).remove(true);
getFileForAddon(profileDir, regexpblock_1.id).remove(true);
startupManager(false);
@ -1261,18 +1350,20 @@ function run_local_install_test() {
do_get_file("addons/blocklist_soft3_1.xpi"),
do_get_file("addons/blocklist_soft4_1.xpi"),
do_get_file("addons/blocklist_soft5_1.xpi"),
do_get_file("addons/blocklist_hard1_1.xpi")
do_get_file("addons/blocklist_hard1_1.xpi"),
do_get_file("addons/blocklist_regexp1_1.xpi")
], function() {
AddonManager.getAllInstalls(function(aInstalls) {
// Should have finished all installs without needing to restart
do_check_eq(aInstalls.length, 0);
AddonManager.getAddonsByIDs(ADDON_IDS, function([s1, s2, s3, s4, s5, h]) {
AddonManager.getAddonsByIDs(ADDON_IDS, function([s1, s2, s3, s4, s5, h, r]) {
check_addon(s1, "1.0", true, true, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
check_addon(s2, "1.0", true, true, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
check_addon(s3, "1.0", true, true, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
check_addon(h, "1.0", false, false, Ci.nsIBlocklistService.STATE_BLOCKED);
check_addon(r, "1.0", false, false, Ci.nsIBlocklistService.STATE_BLOCKED);
end_test();
});

View File

@ -17,6 +17,8 @@ skip-if = os == "android"
[test_blocklistchange.js]
# Bug 676992: test consistently hangs on Android
skip-if = os == "android"
[test_blocklist_regexp.js]
skip-if = os == "android"
[test_bootstrap.js]
# Bug 676992: test consistently hangs on Android
skip-if = os == "android"