test-unload.js 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161
  1. /* This Source Code Form is subject to the terms of the Mozilla Public
  2. * License, v. 2.0. If a copy of the MPL was not distributed with this
  3. * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
  4. "use strict";
  5. var unload = require("sdk/system/unload");
  6. var { Loader, LoaderWithHookedConsole } = require("sdk/test/loader");
  7. exports.testUnloading = function(assert) {
  8. let { loader, messages } = LoaderWithHookedConsole(module);
  9. var ul = loader.require("sdk/system/unload");
  10. var unloadCalled = 0;
  11. function unload() {
  12. unloadCalled++;
  13. throw new Error("error");
  14. }
  15. ul.when(unload);
  16. // This should be ignored, as we already registered it
  17. ul.when(unload);
  18. function unload2() { unloadCalled++; }
  19. ul.when(unload2);
  20. loader.unload();
  21. assert.equal(unloadCalled, 2,
  22. "Unloader functions are called on unload.");
  23. assert.equal(messages.length, 1,
  24. "One unload handler threw exception 1/2");
  25. assert.equal(messages[0].type, "exception",
  26. "One unload handler threw exception 2/2");
  27. };
  28. exports.testEnsure = function(assert) {
  29. assert.throws(function() { unload.ensure({}); },
  30. /object has no 'unload' property/,
  31. "passing obj with no unload prop should fail");
  32. assert.throws(function() { unload.ensure({}, "destroy"); },
  33. /object has no 'destroy' property/,
  34. "passing obj with no custom unload prop should fail");
  35. var called = 0;
  36. var obj = {unload: function() { called++; }};
  37. unload.ensure(obj);
  38. obj.unload();
  39. assert.equal(called, 1,
  40. "unload() should be called");
  41. obj.unload();
  42. assert.equal(called, 1,
  43. "unload() should be called only once");
  44. };
  45. /**
  46. * Check that destructors are called only once with Traits.
  47. * - check that public API is calling the destructor and unregister it,
  48. * - check that composed traits with multiple ensure calls, leads to only
  49. * one destructor call.
  50. */
  51. exports.testEnsureWithTraits = function(assert) {
  52. let { Trait } = require("sdk/deprecated/traits");
  53. let loader = Loader(module);
  54. let ul = loader.require("sdk/system/unload");
  55. let called = 0;
  56. let composedCalled = 0;
  57. let composedTrait = Trait.compose({
  58. constructor: function () {
  59. // We have to give "public interface" of this trait, as we want to
  60. // call public `unload` method and ensure that we call it only once,
  61. // either when we call this public function manually or on add-on unload
  62. ul.ensure(this._public);
  63. },
  64. unload: function unload() {
  65. composedCalled++;
  66. }
  67. });
  68. let obj = Trait.compose(
  69. composedTrait.resolve({
  70. constructor: "_constructor",
  71. unload : "_unload"
  72. }), {
  73. constructor: function constructor() {
  74. // Same thing applies here, we need to pass public interface
  75. ul.ensure(this._public);
  76. this._constructor();
  77. },
  78. unload: function unload() {
  79. called++;
  80. this._unload();
  81. }
  82. })();
  83. obj.unload();
  84. assert.equal(called, 1,
  85. "unload() should be called");
  86. assert.equal(composedCalled, 1,
  87. "composed object unload() should be called");
  88. obj.unload();
  89. assert.equal(called, 1,
  90. "unload() should be called only once");
  91. assert.equal(composedCalled, 1,
  92. "composed object unload() should be called only once");
  93. loader.unload();
  94. assert.equal(called, 1,
  95. "unload() should be called only once, after addon unload");
  96. assert.equal(composedCalled, 1,
  97. "composed object unload() should be called only once, " +
  98. "after addon unload");
  99. };
  100. exports.testEnsureWithTraitsPrivate = function(assert) {
  101. let { Trait } = require("sdk/deprecated/traits");
  102. let loader = Loader(module);
  103. let ul = loader.require("sdk/system/unload");
  104. let called = 0;
  105. let privateObj = null;
  106. let obj = Trait.compose({
  107. constructor: function constructor() {
  108. // This time wa don't have to give public interface,
  109. // as we want to call a private method:
  110. ul.ensure(this, "_unload");
  111. privateObj = this;
  112. },
  113. _unload: function unload() {
  114. called++;
  115. this._unload();
  116. }
  117. })();
  118. loader.unload();
  119. assert.equal(called, 1,
  120. "unload() should be called");
  121. privateObj._unload();
  122. assert.equal(called, 1,
  123. "_unload() should be called only once, after addon unload");
  124. };
  125. exports.testReason = function (assert) {
  126. var reason = "Reason doesn't actually have to be anything in particular.";
  127. var loader = Loader(module);
  128. var ul = loader.require("sdk/system/unload");
  129. ul.when(function (rsn) {
  130. assert.equal(rsn, reason,
  131. "when() reason should be reason given to loader");
  132. });
  133. var obj = {
  134. unload: function (rsn) {
  135. assert.equal(rsn, reason,
  136. "ensure() reason should be reason given to loader");
  137. }
  138. };
  139. ul.ensure(obj);
  140. loader.unload(reason);
  141. };
  142. require("sdk/test").run(exports);