Bug 272640: attendee support, and some cleanups.

- calIAttendee interface
- calAttendee impl
- attendee-related methods on calIItemBase
- basic test suite for attendee stuff
- data-driven component/module/script loading and factory stuff
- suppress component loader error from it trying to load calEvent.js as a
  component
- "make rebuild" target to rebuild .js from .js.pre
- chain calEvent's QI through its proto's

r=vlad,tab-police=mvl
This commit is contained in:
shaver%mozilla.org 2004-12-01 20:52:31 +00:00
parent 1a70059dd4
commit c2768a9ef2
13 changed files with 540 additions and 94 deletions

View File

@ -20,6 +20,7 @@
#
# Contributor(s):
# Dan Mosedale <dan.mosedale@oracle.com>
# Mike Shaver <shaver@off.net>
#
# Alternatively, the contents of this file may be used under the terms of
# either the GNU General Public License Version 2 or later (the "GPL"), or
@ -45,13 +46,14 @@ include $(DEPTH)/config/autoconf.mk
MODULE = calbase
XPIDL_MODULE = calbase
XPIDLSRCS = calIDateTime.idl \
calIItemBase.idl \
calITodo.idl \
calIEvent.idl \
XPIDLSRCS = calIAttendee.idl \
calICalendar.idl \
calIDateTime.idl \
calIEvent.idl \
calIICSService.idl \
calIItemBase.idl \
calIRecurrenceInfo.idl \
calITodo.idl \
$(NULL)
EXPORTS = calBaseCID.h

View File

@ -21,6 +21,7 @@
*
* Contributor(s):
* Vladimir Vukicevic <vladimir.vukicevic@oracle.com>
* Mike Shaver <shaver@off.net>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
@ -61,4 +62,9 @@
#define CAL_TODO_CONTRACTID \
"@mozilla.org/calendar/todo;1"
#define CAL_ATTENDEE_CID \
{ 0x5c8dcaa3, 0x170c, 0x 4a73, { 0x81, 0x42, 0xd5, 0x31, 0x15, 0x6f, 0x66, 0x4d } }
#define CAL_ATTENDEE_CONTRACTID \
"@mozilla.org/calendar/attendee;1"
#endif /* CALBASECID_H_ */

View File

@ -0,0 +1,74 @@
/* -*- Mode: idl; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Oracle Corporation code.
*
* The Initial Developer of the Original Code is
* Oracle Corporation
* Portions created by the Initial Developer are Copyright (C) 2004
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Mike Shaver <shaver@off.net>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#include "nsISupports.idl"
[scriptable,uuid(5d1f2c7c-29bb-4090-94c2-cabe278fe567)]
interface calIAttendee : nsISupports
{
readonly attribute boolean isMutable;
// makes this item immutable
void makeImmutable();
// clone always returns a mutable event
calIAttendee clone();
attribute AUTF8String id;
attribute AUTF8String commonName;
attribute boolean rsvp;
const PRUint32 ROLE_CHAIR = 20041;
const PRUint32 ROLE_REQ_PARTICIPANT = 20042;
const PRUint32 ROLE_OPT_PARTICIPANT = 20043;
const PRUint32 ROLE_NON_PARTICIPANT = 20044;
attribute PRUint32 role;
const PRUint32 PARTSTAT_NEEDSACTION = 20018;
const PRUint32 PARTSTAT_ACCEPTED = 20019;
const PRUint32 PARTSTAT_DECLINED = 20020;
const PRUint32 PARTSTAT_NONE = 20025;
attribute PRUint32 participationStatus;
const PRUint32 CUTYPE_INDIVIDUAL = 20001;
const PRUint32 CUTYPE_GROUP = 20002;
const PRUint32 CUTYPE_RESOURCE = 20003;
const PRUint32 CUTYPE_ROOM = 20004;
attribute PRUint32 userType;
};

View File

@ -56,6 +56,8 @@ interface calIMutableDateTime;
interface calIRecurrenceInfo;
interface calIMutableRecurrenceInfo;
interface calIAttendee;
//
// calIItemBase
//
@ -164,6 +166,14 @@ interface calIItemBase : nsISupports
nsIVariant getProperty(in AString name);
void setProperty(in AString name, in nsIVariant value);
void deleteProperty(in AString name);
// The array returned here is not live; it will not reflect calls to
// removeAttendee/addAttendee that follow the call to getAttendees.
void getAttendees(out PRUint32 count,
[array,size_is(count),retval] out calIAttendee attendees);
calIAttendee getAttendeeById(in AUTF8String id);
void removeAttendee(in calIAttendee attendee);
void addAttendee(in calIAttendee attendee);
};
//

View File

@ -66,8 +66,9 @@ CPPSRCS = calDateTime.cpp \
EXTRA_COMPONENTS = \
calItemBase.js \
calAttendee.js \
calEvent.js \
calItemBase.js \
calItemModule.js \
$(NULL)
@ -75,3 +76,12 @@ include $(topsrcdir)/config/rules.mk
#%.js: %.js.pre
# cpp -P -undef $(DEFINES) $(ACDEFINES) $^ > $@
CPP_FODDER = calItemBase calEvent calAttendee
rebuild:
for i in $(CPP_FODDER); do \
(echo "/* GENERATED FILE; DO NOT EDIT. SOURCE IS $$i.js.pre */"; \
cpp -P -undef $(DEFINES) $(ACDEFINES) $(srcdir)/$$i.js.pre) \
> $(srcdir)/$$i.js; \
done

View File

@ -0,0 +1,50 @@
/* GENERATED FILE; DO NOT EDIT. SOURCE IS calAttendee.js.pre */
function calAttendee() {
this.wrappedJSObject = this;
}
calAttendee.prototype = {
QueryInterface: function (aIID) {
if (!aIID.equals(Components.interfaces.nsISupports) &&
!aIID.equals(Components.interfaces.calIAttendee))
{
throw Components.results.NS_ERROR_NO_INTERFACE;
}
return this;
},
mImmutable: false,
get isMutable() { return !this.mImmutable; },
makeImmutable : function() {
this.mImmutable = true;
},
clone: function() {
var a = new calAttendee();
var allProps = ["id", "commonName", "rsvp", "role", "participantStatus",
"userType"];
for (var i in allProps)
a[allProps[i]] = this[allProps[i]];
return a;
},
mId: null, get id() { return this.mId; }, set id(v) { if (this.mImmutable) throw Components.results.NS_ERROR_FAILURE; else this.mId = v; },
mCommonName: null, get commonName() { return this.mCommonName; }, set commonName(v) { if (this.mImmutable) throw Components.results.NS_ERROR_FAILURE; else this.mCommonName = v; },
mRsvp: false, get rsvp() { return this.mRsvp; }, set rsvp(v) { if (this.mImmutable) throw Components.results.NS_ERROR_FAILURE; else this.mRsvp = v; },
mRole: Components.interfaces.calIAttendee.ROLE_OPT_PARTICIPANT, get role() { return this.mRole; }, set role(v) { if (this.mImmutable) throw Components.results.NS_ERROR_FAILURE; else this.mRole = v; },
mRole: Components.interfaces.calIAttendee.ROLE_OPT_PARTICIPANT, get role() { return this.mRole; }, set role(v) { if (this.mImmutable) throw Components.results.NS_ERROR_FAILURE; else this.mRole = v; },
mParticipationStatus: Components.interfaces.calIAttendee.PARTSTAT_NEEDSACTION, get participationStatus() { return this.mParticipationStatus; }, set participationStatus(v) { if (this.mImmutable) throw Components.results.NS_ERROR_FAILURE; else this.mParticipationStatus = v; },
mUserType: Components.interfaces.calIAttendee.CUTYPE_INDIVIDUAL, get userType() { return this.mUserType; }, set userType(v) { if (this.mImmutable) throw Components.results.NS_ERROR_FAILURE; else this.mUserType = v; }
};

View File

@ -0,0 +1,87 @@
/* -*- Mode: javascript; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Oracle Corporation code.
*
* The Initial Developer of the Original Code is
* Oracle Corporation
* Portions created by the Initial Developer are Copyright (C) 2004
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Mike Shaver <shaver@off.net>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
function calAttendee() {
this.wrappedJSObject = this;
}
calAttendee.prototype = {
QueryInterface: function (aIID) {
if (!aIID.equals(Components.interfaces.nsISupports) &&
!aIID.equals(Components.interfaces.calIAttendee))
{
throw Components.results.NS_ERROR_NO_INTERFACE;
}
return this;
},
mImmutable: false,
get isMutable() { return !this.mImmutable; },
makeImmutable : function() {
this.mImmutable = true;
},
clone: function() {
var a = new calAttendee();
var allProps = ["id", "commonName", "rsvp", "role", "participantStatus",
"userType"];
for (var i in allProps)
a[allProps[i]] = this[allProps[i]];
return a;
},
#define MEMBER_ATTR(varname, initvalue, attrname) \
varname: initvalue, \
get attrname() { return this.varname; }, \
set attrname(v) { if (this.mImmutable) throw Components.results.NS_ERROR_FAILURE; else this.varname = v; }
MEMBER_ATTR(mId, null, id),
MEMBER_ATTR(mCommonName, null, commonName),
MEMBER_ATTR(mRsvp, false, rsvp),
MEMBER_ATTR(mRole, Components.interfaces.calIAttendee.ROLE_OPT_PARTICIPANT, role),
MEMBER_ATTR(mRole, Components.interfaces.calIAttendee.ROLE_OPT_PARTICIPANT, role),
MEMBER_ATTR(mParticipationStatus,
Components.interfaces.calIAttendee.PARTSTAT_NEEDSACTION,
participationStatus),
MEMBER_ATTR(mUserType, Components.interfaces.calIAttendee.CUTYPE_INDIVIDUAL, userType)
#undef MEMBER_ATTR
};

View File

@ -1,21 +1,21 @@
/* GENERATED FILE; DO NOT EDIT. SOURCE IS calEvent.js.pre */
function calEvent() {
this.wrappedJSObject = this;
this.initItemBase();
this.initEvent();
}
var calItemBase;
calEvent.prototype = {
__proto__: (new calItemBase()),
__proto__: calItemBase ? (new calItemBase()) : {},
QueryInterface: function (aIID) {
if (!aIID.equals(Components.interfaces.nsISupports) &&
!aIID.equals(Components.interfaces.calIItemBase) &&
!aIID.equals(Components.interfaces.calIEvent))
{
throw Components.results.NS_ERROR_NO_INTERFACE;
}
if (aIID.equals(Components.interfaces.calIEvent))
return this;
return this;
return this.__proto__.QueryInterface(aIID);
},
initEvent: function () {

View File

@ -21,6 +21,7 @@
*
* Contributor(s):
* Vladimir Vukicevic <vladimir.vukicevic@oracle.com>
* Mike Shaver <shaver@off.net>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
@ -49,18 +50,17 @@ function calEvent() {
this.initEvent();
}
// var trickery to suppress lib-as-component errors from loader
var calItemBase;
calEvent.prototype = {
__proto__: (new calItemBase()),
__proto__: calItemBase ? (new calItemBase()) : {},
QueryInterface: function (aIID) {
if (!aIID.equals(Components.interfaces.nsISupports) &&
!aIID.equals(Components.interfaces.calIItemBase) &&
!aIID.equals(Components.interfaces.calIEvent))
{
throw Components.results.NS_ERROR_NO_INTERFACE;
}
if (aIID.equals(Components.interfaces.calIEvent))
return this;
return this;
return this.__proto__.QueryInterface(aIID);
},
initEvent: function () {

View File

@ -1,3 +1,4 @@
/* GENERATED FILE; DO NOT EDIT. SOURCE IS calItemBase.js.pre */
function calItemBase() { }
calItemBase.prototype = {
@ -26,6 +27,8 @@ calItemBase.prototype = {
if (this.mAlarmTime)
this.mAlarmTime.makeImmutable();
for (var i = 0; i < this.mAttendees.length; i++)
this.mAttendees[i].makeImmutable();
this.mImmutable = true;
},
@ -37,6 +40,8 @@ calItemBase.prototype = {
this.mProperties = Components.classes["@mozilla.org/hash-property-bag;1"].
createInstance(Components.interfaces.nsIWritablePropertyBag);
this.mAttendees = [];
this.mRecurrenceInfo = null;
this.mAttachments = null;
@ -112,6 +117,37 @@ calItemBase.prototype = {
if (this.mImmutable)
throw Components.results.NS_ERROR_FAILURE;
this.mProperties.deleteProperty(aName);
},
getAttendees: function (countObj) {
countObj.value = this.mAttendees.length;
return this.mAttendees.concat([]);
},
getAttendeeById: function (id) {
for (var i = 0; i < this.mAttendees.length; i++)
if (this.mAttendees[i].id == id)
return this.mAttendees[i];
return null;
},
removeAttendee: function (attendee) {
if (this.mImmutable)
throw Components.results.NS_ERROR_FAILURE;
var found = false, newAttendees = [];
for (var i = 0; i < this.mAttendees.length; i++) {
if (this.mAttendees[i] != attendee)
newAttendees.push(this.mAttendees[i]);
else
found = true;
}
if (found)
this.mAttendees = newAttendees;
else
throw Component.results.NS_ERROR_INVALID_ARG;
},
addAttendee: function (attendee) {
if (this.mImmutable)
throw Components.results.NS_ERROR_FAILURE;
this.mAttendees.push(attendee);
}
};

View File

@ -21,6 +21,7 @@
*
* Contributor(s):
* Vladimir Vukicevic <vladimir.vukicevic@oracle.com>
* Mike Shaver <shaver@off.net>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
@ -68,6 +69,8 @@ calItemBase.prototype = {
if (this.mAlarmTime)
this.mAlarmTime.makeImmutable();
for (var i = 0; i < this.mAttendees.length; i++)
this.mAttendees[i].makeImmutable();
this.mImmutable = true;
},
@ -79,6 +82,8 @@ calItemBase.prototype = {
this.mProperties = Components.classes["@mozilla.org/hash-property-bag;1"].
createInstance(Components.interfaces.nsIWritablePropertyBag);
this.mAttendees = [];
// fix me
this.mRecurrenceInfo = null;
this.mAttachments = null;
@ -154,6 +159,37 @@ calItemBase.prototype = {
if (this.mImmutable)
throw Components.results.NS_ERROR_FAILURE;
this.mProperties.deleteProperty(aName);
},
getAttendees: function (countObj) {
countObj.value = this.mAttendees.length;
return this.mAttendees.concat([]); // clone
},
getAttendeeById: function (id) {
for (var i = 0; i < this.mAttendees.length; i++)
if (this.mAttendees[i].id == id)
return this.mAttendees[i];
return null;
},
removeAttendee: function (attendee) {
if (this.mImmutable)
throw Components.results.NS_ERROR_FAILURE;
var found = false, newAttendees = [];
for (var i = 0; i < this.mAttendees.length; i++) {
if (this.mAttendees[i] != attendee)
newAttendees.push(this.mAttendees[i]);
else
found = true;
}
if (found)
this.mAttendees = newAttendees;
else
throw Component.results.NS_ERROR_INVALID_ARG;
},
addAttendee: function (attendee) {
if (this.mImmutable)
throw Components.results.NS_ERROR_FAILURE;
this.mAttendees.push(attendee);
}
};

View File

@ -36,17 +36,37 @@
*
* ***** END LICENSE BLOCK ***** */
/* Update these in calBaseCID.h */
const componentData =
[
/* calItemBase must be first: later scripts depend on it */
{cid: null,
contractid: null,
script: "calItemBase.js",
constructor: null},
{cid: Components.ID("{974339d5-ab86-4491-aaaf-2b2ca177c12b}"),
contractid: "@mozilla.org/calendar/event;1",
script: "calEvent.js",
constructor: "calEvent"},
{cid: Components.ID("{7af51168-6abe-4a31-984d-6f8a3989212d}"),
contractid: "@mozilla.org/calendar/todo;1",
script: null,
constructor: "calTodo"},
{cid: Components.ID("{bad672b3-30b8-4ecd-8075-7153313d1f2c}"),
contractid: "@mozilla.org/calendar/item-occurrence;1",
script: null,
constructor: "calItemOccurrence"},
{cid: Components.ID("{5c8dcaa3-170c-4a73-8142-d531156f664d}"),
contractid: "@mozilla.org/calendar/attendee;1",
script: "calAttendee.js",
constructor: "calAttendee"}
];
var calItemModule = {
/* Update these in calBaseCID.h */
mEventCID: Components.ID("{974339d5-ab86-4491-aaaf-2b2ca177c12b}"),
mEventContractId: "@mozilla.org/calendar/event;1",
mTodoCID: Components.ID("{7af51168-6abe-4a31-984d-6f8a3989212d}"),
mTodoContractId: "@mozilla.org/calendar/todo;1",
mItemOccurrenceCID: Components.ID("{bad672b3-30b8-4ecd-8075-7153313d1f2c}"),
mItemOccurrenceContractId: "@mozilla.org/calendar/item-occurrence;1",
mScriptsLoaded: false,
loadScripts: function () {
if (this.mScriptsLoaded)
@ -67,11 +87,14 @@ var calItemModule = {
// NS_XPCOM_COMPONENT_DIR
var appdir = dirsvc.get("ComsD", Components.interfaces.nsIFile);
var files = [ "calItemBase.js", "calEvent.js" ];
for (var i = 0; i < files.length; i++) {
for (var i = 0; i < componentData.length; i++) {
var scriptName = componentData[i].script;
if (!scriptName)
continue;
var f = appdir.clone();
f.append(files[i]);
f.append(scriptName);
var fileurl = iosvc.newFileURI(f);
loader.loadSubScript(fileurl.spec, null);
@ -83,20 +106,39 @@ var calItemModule = {
registerSelf: function (compMgr, fileSpec, location, type) {
compMgr = compMgr.QueryInterface(Components.interfaces.nsIComponentRegistrar);
var cids = [ this.mEventCID, this.mTodoCID, this.mItemOccurrenceCID ];
var contractids = [ this.mEventContractId, this.mTodoContractId, this.mItemOccurrenceContractId ];
for (var i = 0; i < cids.length; i++) {
dump ("calItemModule: registering " + contractids[i] + "\n");
compMgr.registerFactoryLocation(cids[i],
for (var i = 0; i < componentData.length; i++) {
var comp = componentData[i];
if (!comp.cid)
continue;
dump ("calItemModule: registering " + comp.contractid + "\n");
compMgr.registerFactoryLocation(comp.cid,
"",
contractids[i],
comp.contractid,
fileSpec,
location,
type);
}
},
makeFactoryFor: function(constructor) {
var factory = {
QueryInterface: function (aIID) {
if (!aIID.equals(Components.interfaces.nsISupports) &&
!aIID.equals(Components.interfaces.nsIFactory))
throw Components.results.NS_ERROR_NO_INTERFACE;
return this;
},
createInstance: function (outer, iid) {
if (outer != null)
throw Components.results.NS_ERROR_NO_AGGREGATION;
return (new constructor()).QueryInterface(iid);
}
};
return factory;
},
getClassObject: function (compMgr, cid, iid) {
if (!iid.equals(Components.interfaces.nsIFactory))
throw Components.results.NS_ERROR_NOT_IMPLEMENTED;
@ -104,63 +146,15 @@ var calItemModule = {
if (!this.mScriptsLoaded)
this.loadScripts();
if (cid.equals(this.mEventCID))
return this.mEventFactory;
if (cid.equals(this.mTodoCID))
return this.mTodoFactory;
if (cid.equals(this.mItemOccurrenceCID))
return this.mItemOccurrenceFactory;
for (var i = 0; i < componentData.length; i++) {
if (cid.equals(componentData[i].cid))
// eval to get usual scope-walking
return this.makeFactoryFor(eval(componentData[i].constructor));
}
throw Components.results.NS_ERROR_NO_INTERFACE;
},
mEventFactory: {
QueryInterface: function (aIID) {
if (!aIID.equals(Components.interfaces.nsISupports) &&
!aIID.equals(Components.interfaces.nsIFactory))
throw Components.results.NS_ERROR_NO_INTERFACE;
return this;
},
createInstance: function (outer, iid) {
if (outer != null)
throw Components.results.NS_ERROR_NO_AGGREGATION;
return (new calEvent()).QueryInterface(iid);
}
},
mTodoFactory: {
QueryInterface: function (aIID) {
if (!aIID.equals(Components.interfaces.nsISupports) &&
!aIID.equals(Components.interfaces.nsIFactory))
throw Components.results.NS_ERROR_NO_INTERFACE;
return this;
},
createInstance: function (outer, iid) {
if (outer != null)
throw Components.results.NS_ERROR_NO_AGGREGATION;
return (new calTodo()).QueryInterface(iid);
}
},
mItemOccurrenceFactory: {
QueryInterface: function (aIID) {
if (!aIID.equals(Components.interfaces.nsISupports) &&
!aIID.equals(Components.interfaces.nsIFactory))
throw Components.results.NS_ERROR_NO_INTERFACE;
return this;
},
createInstance: function (outer, iid) {
if (outer != null)
throw Components.results.NS_ERROR_NO_AGGREGATION;
return (new calItemOccurrence()).QueryInterface(iid);
}
},
canUnload: function(compMgr) {
return true;
}

View File

@ -0,0 +1,141 @@
var C = Components;
var eventClass = C.classes["@mozilla.org/calendar/event;1"];
var eventIID = C.interfaces.calIEvent;
var attendeeClass = C.classes["@mozilla.org/calendar/attendee;1"];
var attendeeIID = C.interfaces.calIAttendee;
dump("* Creating event.\n");
var e = eventClass.createInstance(eventIID);
dump("* Creating attendee.\n");
var a1 = attendeeClass.createInstance(attendeeIID);
dump("* Testing attendee set/get.\n");
var properties = ["id", "commonName", "rsvp", "role", "participationStatus",
"userType"];
var values = ["myid", "mycn", true, attendeeIID.ROLE_CHAIR,
attendeeIID.PARTSTAT_DECLINED,
attendeeIID.CUTYPE_RESOURCE];
if (properties.length != values.length)
throw "Test bug: mismatched properties and values arrays!";
for (var i = 0; i < properties.length; i++) {
a1[properties[i]] = values[i];
if (a1[properties[i]] != values[i]) {
throw "FAILURE: " + properties[i] + " not set to " + values[i];
}
}
dump("* Adding attendee to event.\n");
e.addAttendee(a1);
dump("* Adding 2nd attendee to event.\n");
var a2 = attendeeClass.createInstance(attendeeIID);
a2.id = "myid2";
e.addAttendee(a2);
dump("* Finding by ID.\n");
function findById(id, a) {
var foundAttendee = e.getAttendeeById(id);
if (foundAttendee != a) {
throw "FAILURE: wrong attendee returned for + '" +
id + "' (got " + foundAttendee + ", expected " + a + ")";
}
}
findById("myid", a1);
findById("myid2", a2);
dump("* Searching getAttendees results\n");
var found1, found2;
function findAttendeesInResults(expectedCount) {
if (expectedCount == undefined)
throw "TEST BUG: expectedCount not passed to findAttendeesInResults";
var countObj = {};
dump(" Getting all attendees.\n");
var allAttendees = e.getAttendees(countObj);
if (countObj.value != allAttendees.length) {
throw "FAILURE: out count (" + countObj.value + ") != .length (" +
allAttendees.length + ")";
}
if (allAttendees.length != expectedCount) {
throw "FAILURE: expected to get back " + expectedCount +
" attendees, got " + allAttendees.length;
}
found1 = false, found2 = false;
for (var i = 0; i < expectedCount; i++) {
if (allAttendees[i] == a1)
found1 = true;
else if (allAttendees[i] == a2)
found2 = true;
else {
throw "FAILURE: unknown attendee " + allAttendees[i] +
" (we added " + a1 + " and " + a2 + + ")";
}
}
}
findAttendeesInResults(2);
if (!found1)
throw "FAILURE: didn't find attendee1 (" + a1 + ") in results";
if (!found2)
throw "FAILURE: didn't find attendee2 (" + a2 + ") in results";
dump("* Removing attendee.\n");
e.removeAttendee(a1);
if (e.getAttendeeById(a1.id) != null)
throw "FAILURE: got back removed attendee " + a1 + " by id";
findById("myid2", a2);
found1 = false, found2 = false;
findAttendeesInResults(1);
if (found1)
throw "FAILURE: found removed attendee " + a1 + " in getAttendees results";
if (!found2) {
throw "FAILURE: didn't find remaining attendee " + a2 +
" in getAttendees results";
}
dump("* Readding attendee.\n");
e.addAttendee(a1);
findById("myid", a1);
findById("myid2", a2);
findAttendeesInResults(2);
if (!found1)
throw "FAILURE: didn't find attendee1 (" + a1 + ") in results";
if (!found2)
throw "FAILURE: didn't find attendee2 (" + a2 + ") in results";
dump("* Making attendee immutable.\n");
a1.makeImmutable();
function testImmutability(a) {
if (a.isMutable) {
throw "FAILURE: Attendee " + a +
" should be immutable, but claims otherwise";
}
for (var i = 0; i < properties.length; i++) {
var old = a[properties[i]];
var threw;
try {
a[properties[i]] = old + 1;
threw = false;
} catch (e) {
threw = true;
}
if (!threw) {
throw "FAILURE: no error thrown setting " + properties[i] +
"on immutable attendee " + a;
}
if (a[properties[i]] != old) {
throw "FAILURE: setting " + properties[i] + " on " + a +
" threw, but changed value anyway!";
}
}
}
testImmutability(a1);
dump("* Testing cascaded immutability (event -> attendee).\n");
e.makeImmutable();
testImmutability(a2);
dump("PASSED!\n");