Bug 1433802 - Move listeners and property bags into calDataUtils.jsm - fix regression and add unit tests. r=MakeMyDay
MozReview-Commit-ID: K4f9XBs11Bw
This commit is contained in:
Родитель
1483bb775a
Коммит
2340f43102
|
@ -10,25 +10,26 @@ this.EXPORTED_SYMBOLS = ["caldata"]; /* exported caldata */
|
||||||
|
|
||||||
class PropertyMap extends Map {
|
class PropertyMap extends Map {
|
||||||
get simpleEnumerator() {
|
get simpleEnumerator() {
|
||||||
let iter = this.entries();
|
let entries = [...this.entries()].filter(([key, value]) => value !== undefined);
|
||||||
return {
|
let index = 0;
|
||||||
current: null,
|
|
||||||
|
|
||||||
|
return {
|
||||||
QueryInterface: XPCOMUtils.generateQI([Components.interfaces.nsISimpleEnumerator]),
|
QueryInterface: XPCOMUtils.generateQI([Components.interfaces.nsISimpleEnumerator]),
|
||||||
|
|
||||||
hasMoreElements: function() {
|
hasMoreElements: function() {
|
||||||
this.current = iter.next();
|
return index < entries.length;
|
||||||
return !this.current.done;
|
|
||||||
},
|
},
|
||||||
|
|
||||||
getNext: function() {
|
getNext: function() {
|
||||||
if (!this.current || this.current.done) {
|
if (!this.hasMoreElements()) {
|
||||||
throw Components.results.NS_ERROR_UNEXPECTED;
|
throw Components.results.NS_ERROR_UNEXPECTED;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let [name, value] = entries[index++];
|
||||||
return {
|
return {
|
||||||
QueryInterface: XPCOMUtils.generateQI([Components.interfaces.nsIProperty]),
|
QueryInterface: XPCOMUtils.generateQI([Components.interfaces.nsIProperty]),
|
||||||
name: this.current.value[0],
|
name: name,
|
||||||
value: this.current.value[1]
|
value: value
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -45,12 +46,17 @@ class ListenerSet extends Set {
|
||||||
super.add(item.QueryInterface(this.mIID));
|
super.add(item.QueryInterface(this.mIID));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
has(item) {
|
||||||
|
return super.has(item.QueryInterface(this.mIID));
|
||||||
|
}
|
||||||
|
|
||||||
delete(item) {
|
delete(item) {
|
||||||
super.delete(item.QueryInterface(this.mIID));
|
super.delete(item.QueryInterface(this.mIID));
|
||||||
}
|
}
|
||||||
|
|
||||||
notify(func, args=[]) {
|
notify(func, args=[]) {
|
||||||
for (let observer of this.values()) {
|
let currentObservers = [...this.values()];
|
||||||
|
for (let observer of currentObservers) {
|
||||||
try {
|
try {
|
||||||
observer[func](...args);
|
observer[func](...args);
|
||||||
} catch (exc) {
|
} catch (exc) {
|
||||||
|
@ -67,6 +73,10 @@ class ObserverSet extends ListenerSet {
|
||||||
this.mBatchCount = 0;
|
this.mBatchCount = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get batchCount() {
|
||||||
|
return this.mBatchCount;
|
||||||
|
}
|
||||||
|
|
||||||
notify(func, args=[]) {
|
notify(func, args=[]) {
|
||||||
switch (func) {
|
switch (func) {
|
||||||
case "onStartBatch":
|
case "onStartBatch":
|
||||||
|
@ -80,7 +90,7 @@ class ObserverSet extends ListenerSet {
|
||||||
}
|
}
|
||||||
|
|
||||||
add(item) {
|
add(item) {
|
||||||
if (this.has(item)) {
|
if (!this.has(item) && this.mBatchCount > 0) {
|
||||||
// Replay batch notifications, because the onEndBatch notifications are yet to come.
|
// Replay batch notifications, because the onEndBatch notifications are yet to come.
|
||||||
// We may think about doing the reverse on remove, though I currently see no need:
|
// We may think about doing the reverse on remove, though I currently see no need:
|
||||||
for (let i = this.mBatchCount; i; i--) {
|
for (let i = this.mBatchCount; i; i--) {
|
||||||
|
|
|
@ -0,0 +1,183 @@
|
||||||
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
function run_test() {
|
||||||
|
test_property_map();
|
||||||
|
test_listener_set();
|
||||||
|
test_observer_set();
|
||||||
|
test_operation_group();
|
||||||
|
}
|
||||||
|
|
||||||
|
function test_property_map() {
|
||||||
|
let data = {
|
||||||
|
key1: "value1",
|
||||||
|
key2: undefined,
|
||||||
|
key3: "value2"
|
||||||
|
};
|
||||||
|
|
||||||
|
let map = new cal.data.PropertyMap(Object.entries(data));
|
||||||
|
let keys = new Set(Object.keys(data));
|
||||||
|
|
||||||
|
let enumerator = map.simpleEnumerator;
|
||||||
|
|
||||||
|
while (enumerator.hasMoreElements()) {
|
||||||
|
let next = enumerator.getNext();
|
||||||
|
ok(keys.has(next.name));
|
||||||
|
equal(data[next.name], next.value);
|
||||||
|
|
||||||
|
keys.delete(next.name);
|
||||||
|
|
||||||
|
// An extra hasMoreElements shouldn't disrupt the enumeration
|
||||||
|
enumerator.hasMoreElements();
|
||||||
|
}
|
||||||
|
|
||||||
|
equal(keys.size, 1);
|
||||||
|
ok(keys.has("key2"));
|
||||||
|
|
||||||
|
throws(() => {
|
||||||
|
enumerator.getNext();
|
||||||
|
}, code => code == Components.results.NS_ERROR_UNEXPECTED);
|
||||||
|
}
|
||||||
|
|
||||||
|
function test_listener_set() {
|
||||||
|
let set = new cal.data.ListenerSet(Components.interfaces.calIOperationListener);
|
||||||
|
let listener1Id = null;
|
||||||
|
let listener2Id = null;
|
||||||
|
|
||||||
|
let listener1 = cal.createAdapter("calIOperationListener", {
|
||||||
|
onOperationComplete: function(aCalendar, aStatus, aOpType, aId, aDetail) {
|
||||||
|
listener1Id = aId;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
let listener2 = cal.createAdapter("calIOperationListener", {
|
||||||
|
onOperationComplete: function(aCalendar, aStatus, aOpType, aId, aDetail) {
|
||||||
|
listener2Id = aId;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
set.add(listener1);
|
||||||
|
set.add(listener2);
|
||||||
|
set.notify("onOperationComplete", [null, null, null, "test", null]);
|
||||||
|
equal(listener1Id, "test");
|
||||||
|
equal(listener2Id, "test");
|
||||||
|
|
||||||
|
set.delete(listener2);
|
||||||
|
listener1Id = listener2Id = null;
|
||||||
|
set.notify("onOperationComplete", [null, null, null, "test2", null]);
|
||||||
|
equal(listener1Id, "test2");
|
||||||
|
strictEqual(listener2Id, null);
|
||||||
|
|
||||||
|
// Re-adding the listener may lead to an endless loop if the notify
|
||||||
|
// function uses a live list of observers.
|
||||||
|
let called = 0;
|
||||||
|
let listener3 = cal.createAdapter("calIOperationListener", {
|
||||||
|
onOperationComplete: function(aCalendar, aStatus, aOpType, aId, aDetail) {
|
||||||
|
set.delete(listener3);
|
||||||
|
if (called == 0) {
|
||||||
|
set.add(listener3);
|
||||||
|
}
|
||||||
|
called++;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
set.add(listener3);
|
||||||
|
set.notify("onOperationComplete", [null, null, null, "test3", null]);
|
||||||
|
equal(called, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
function test_observer_set() {
|
||||||
|
let set = new cal.data.ObserverSet(Components.interfaces.calIObserver);
|
||||||
|
let listenerCountBegin1 = 0;
|
||||||
|
let listenerCountBegin2 = 0;
|
||||||
|
let listenerCountEnd1 = 0;
|
||||||
|
let listenerCountEnd2 = 0;
|
||||||
|
|
||||||
|
let listener1 = cal.createAdapter("calIObserver", {
|
||||||
|
onStartBatch: function() {
|
||||||
|
listenerCountBegin1++;
|
||||||
|
},
|
||||||
|
onEndBatch: function() {
|
||||||
|
listenerCountEnd1++;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
let listener2 = cal.createAdapter("calIObserver", {
|
||||||
|
onStartBatch: function() {
|
||||||
|
listenerCountBegin2++;
|
||||||
|
},
|
||||||
|
onEndBatch: function() {
|
||||||
|
listenerCountEnd2++;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
set.add(listener1);
|
||||||
|
equal(listenerCountBegin1, 0);
|
||||||
|
equal(listenerCountEnd1, 0);
|
||||||
|
equal(set.batchCount, 0);
|
||||||
|
|
||||||
|
set.notify("onStartBatch");
|
||||||
|
equal(listenerCountBegin1, 1);
|
||||||
|
equal(listenerCountEnd1, 0);
|
||||||
|
equal(set.batchCount, 1);
|
||||||
|
|
||||||
|
set.add(listener2);
|
||||||
|
equal(listenerCountBegin1, 1);
|
||||||
|
equal(listenerCountEnd1, 0);
|
||||||
|
equal(listenerCountBegin2, 1);
|
||||||
|
equal(listenerCountEnd2, 0);
|
||||||
|
equal(set.batchCount, 1);
|
||||||
|
|
||||||
|
set.add(listener1);
|
||||||
|
equal(listenerCountBegin1, 1);
|
||||||
|
equal(listenerCountEnd1, 0);
|
||||||
|
equal(listenerCountBegin2, 1);
|
||||||
|
equal(listenerCountEnd2, 0);
|
||||||
|
equal(set.batchCount, 1);
|
||||||
|
|
||||||
|
set.notify("onEndBatch");
|
||||||
|
equal(listenerCountBegin1, 1);
|
||||||
|
equal(listenerCountEnd1, 1);
|
||||||
|
equal(listenerCountBegin2, 1);
|
||||||
|
equal(listenerCountEnd2, 1);
|
||||||
|
equal(set.batchCount, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
function test_operation_group() {
|
||||||
|
let calledCancel = false;
|
||||||
|
let calledOperationCancel = null;
|
||||||
|
let group = new cal.data.OperationGroup();
|
||||||
|
ok(group.id.endsWith("-0"));
|
||||||
|
ok(group.isPending);
|
||||||
|
equal(group.status, Components.results.NS_OK);
|
||||||
|
ok(group.isEmpty);
|
||||||
|
|
||||||
|
let operation = {
|
||||||
|
id: 123,
|
||||||
|
isPending: true,
|
||||||
|
cancel: (status) => {
|
||||||
|
calledOperationCancel = status;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
group.add(operation);
|
||||||
|
ok(!group.isEmpty);
|
||||||
|
|
||||||
|
group.notifyCompleted(Components.results.NS_ERROR_FAILURE);
|
||||||
|
ok(!group.isPending);
|
||||||
|
equal(group.status, Components.results.NS_ERROR_FAILURE);
|
||||||
|
strictEqual(calledOperationCancel, null);
|
||||||
|
|
||||||
|
group.remove(operation);
|
||||||
|
ok(group.isEmpty);
|
||||||
|
|
||||||
|
group = new cal.data.OperationGroup(() => {
|
||||||
|
calledCancel = true;
|
||||||
|
});
|
||||||
|
ok(group.id.endsWith("-1"));
|
||||||
|
group.add(operation);
|
||||||
|
|
||||||
|
group.cancel();
|
||||||
|
equal(group.status, Components.interfaces.calIErrors.OPERATION_CANCELLED);
|
||||||
|
equal(calledOperationCancel, Components.interfaces.calIErrors.OPERATION_CANCELLED);
|
||||||
|
ok(calledCancel);
|
||||||
|
}
|
|
@ -20,6 +20,7 @@
|
||||||
[test_calmgr.js]
|
[test_calmgr.js]
|
||||||
[test_calutils.js]
|
[test_calutils.js]
|
||||||
[test_calitiputils.js]
|
[test_calitiputils.js]
|
||||||
|
[test_data_bags.js]
|
||||||
[test_datetime.js]
|
[test_datetime.js]
|
||||||
[test_datetime_before_1970.js]
|
[test_datetime_before_1970.js]
|
||||||
[test_datetimeformatter.js]
|
[test_datetimeformatter.js]
|
||||||
|
|
Загрузка…
Ссылка в новой задаче