From beac48c42af93bbff73f481f616cfce2b1eb3b54 Mon Sep 17 00:00:00 2001 From: "dmose%mozilla.org" Date: Fri, 24 Dec 2004 02:02:11 +0000 Subject: [PATCH] Moving test subdirectory from mozilla/calendar/base/test to mozilla/calendar/test; rearranging structure for use with jsDriver.pl. Not part of the build. git-svn-id: svn://10.0.0.236/trunk@167008 18797224-902f-48f8-a5cc-f745e15eee43 --- mozilla/calendar/test/Makefile.in | 82 ++ .../homegrown/memory/add-get-delete-event.js | 49 + .../test/homegrown/memory/getEvents.js | 12 + .../calendar/test/homegrown/memory/shell.js | 4 + .../calendar/test/homegrown/misc/attendee.js | 156 ++ .../test/homegrown/misc/ics-roundtrip.js | 41 + .../homegrown/misc/simple-item-mutability.js | 35 + .../test/homegrown/misc/synchronization.js | 192 +++ mozilla/calendar/test/homegrown/shell.js | 143 ++ mozilla/calendar/test/jsDriver.pl | 1289 +++++++++++++++++ 10 files changed, 2003 insertions(+) create mode 100644 mozilla/calendar/test/Makefile.in create mode 100644 mozilla/calendar/test/homegrown/memory/add-get-delete-event.js create mode 100644 mozilla/calendar/test/homegrown/memory/getEvents.js create mode 100644 mozilla/calendar/test/homegrown/memory/shell.js create mode 100644 mozilla/calendar/test/homegrown/misc/attendee.js create mode 100644 mozilla/calendar/test/homegrown/misc/ics-roundtrip.js create mode 100644 mozilla/calendar/test/homegrown/misc/simple-item-mutability.js create mode 100644 mozilla/calendar/test/homegrown/misc/synchronization.js create mode 100644 mozilla/calendar/test/homegrown/shell.js create mode 100755 mozilla/calendar/test/jsDriver.pl diff --git a/mozilla/calendar/test/Makefile.in b/mozilla/calendar/test/Makefile.in new file mode 100644 index 00000000000..926731ff583 --- /dev/null +++ b/mozilla/calendar/test/Makefile.in @@ -0,0 +1,82 @@ +# +# ***** 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 the 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): +# Dan Mosedale +# +# 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 ***** + +DEPTH = ../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(DEPTH)/config/autoconf.mk + +include $(topsrcdir)/config/rules.mk + +RUN = $(DIST)/bin/run-mozilla.sh +XPCSHELL = $(DIST)/bin/xpcshell + +# once we land the necessary changes in the canonical copy of jsDriver.pl, +# we should add that file to the calendar CVS module, and then switch to the +# commented-out version here +# +#JSDRIVER = $(topsrcdir)/js/tests/jsDriver.pl +# +JSDRIVER = $(srcdir)/jsDriver.pl + +PROVIDER_TESTS = getEvents.js +PROVIDERS = memory caldav +REDIRECTERR = 2>/dev/null +GARBAGE += results*.html + +# for running xpcshell with the calshell objects loaded in +# +.PHONY: calshell +calshell: + $(RUN) $(XPCSHELL) -f $(srcdir)/homegrown/shell.js -f - + +.PHONY: test-providers +test-providers: + +.PHONY: test-misc +test-misc: + +# run all the tests +# +.PHONY: test +test: test-providers test-misc + env MOZILLA_FIVE_HOME=$(DIST)/bin LD_LIBRARY_PATH=$(DIST)/bin \ + $(JSDRIVER) --confail --engine=xpcshell --testpath=$(srcdir) \ + $(REDIRECTERR) + diff --git a/mozilla/calendar/test/homegrown/memory/add-get-delete-event.js b/mozilla/calendar/test/homegrown/memory/add-get-delete-event.js new file mode 100644 index 00000000000..345f70f49c4 --- /dev/null +++ b/mozilla/calendar/test/homegrown/memory/add-get-delete-event.js @@ -0,0 +1,49 @@ +// here's our event, ics-style + +const icsEvent = "BEGIN:VCALENDAR +PRODID:-//ORACLE//NONSGML CSDK 9.0.5 - CalDAVServlet 9.0.5//EN +VERSION:2.0 +BEGIN:VEVENT +UID:uuid:1103314036911 +ORGANIZER;X-ORACLE-GUID=E93594067928763EE0305794071A39A4;CN=Dan Mosedale: + mailto:dan.mosedale@oracle.com +SEQUENCE:0 +DTSTAMP:20041223T032127Z +CREATED:20041217T200716Z +DTSTART:20041215T160000Z +DTEND:20041215T170000Z +X-ORACLE-EVENTINSTANCE-GUID:I1+1093+1+1+440626036 +X-ORACLE-EVENT-GUID:E1+1093+1+440626036 +X-ORACLE-EVENTTYPE:APPOINTMENT +TRANSP:OPAQUE +SUMMARY:monkey +STATUS:CONFIRMED +PRIORITY:0 +CLASS:PUBLIC +ATTENDEE;X-ORACLE-PERSONAL-COMMENT-ISDIRTY=TRUE;X-ORACLE-SHOWASFREE=BUSY; + X-ORACLE-GUID=E93594067928763EE0305794071A39A4;CUTYPE=INDIVIDUAL;RSVP=FA + LSE;CN=Dan Mosedale;PARTSTAT=ACCEPTED:mailto:dan.mosedale@oracle.com +BEGIN:VALARM +TRIGGER:-P0DT0H10M0S +ACTION:DISPLAY +DESCRIPTION:monkey +END:VALARM +BEGIN:VALARM +TRIGGER:-P0DT0H10M0S +ACTION:AUDIO +END:VALARM +END:VEVENT +END:VCALENDAR +"; + + +var cal = createInstance("@mozilla.org/calendar/calendar;1?type=caldav", + CI.calICalendar); +cal.uri = URLFromSpec(calendarUri); + +var listener = new calOpListener(); + +cal.getItem("20041119T052348Z-100040d-1-248609e9-Oracle", listener); + +if (!done) + runEventPump(); diff --git a/mozilla/calendar/test/homegrown/memory/getEvents.js b/mozilla/calendar/test/homegrown/memory/getEvents.js new file mode 100644 index 00000000000..7b3398add68 --- /dev/null +++ b/mozilla/calendar/test/homegrown/memory/getEvents.js @@ -0,0 +1,12 @@ +var cal = createInstance("@mozilla.org/calendar/calendar;1?type=" + + calendarType, CI.calICalendar); +cal.uri = URLFromSpec(calendarUri); + +var listener = new calOpListener(); + +cal.getItems(CI.calICalendar.ITEM_FILTER_COMPLETED_ALL | + CI.calICalendar.ITEM_FILTER_TYPE_EVENT, 0, + null, null, listener); + +if (!done) + runEventPump(); diff --git a/mozilla/calendar/test/homegrown/memory/shell.js b/mozilla/calendar/test/homegrown/memory/shell.js new file mode 100644 index 00000000000..a7a94c73ca9 --- /dev/null +++ b/mozilla/calendar/test/homegrown/memory/shell.js @@ -0,0 +1,4 @@ +calendarType = "memory"; + +calendarUri = "http://this/doesn't/matter/on/memory/calendar/"; + diff --git a/mozilla/calendar/test/homegrown/misc/attendee.js b/mozilla/calendar/test/homegrown/misc/attendee.js new file mode 100644 index 00000000000..c31725bfcd8 --- /dev/null +++ b/mozilla/calendar/test/homegrown/misc/attendee.js @@ -0,0 +1,156 @@ +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 "FAILED! " + 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 "FAILED! 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 "FAILED! out count (" + countObj.value + ") != .length (" + + allAttendees.length + ")"; + } + + if (allAttendees.length != expectedCount) { + throw "FAILED! 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 "FAILED! unknown attendee " + allAttendees[i] + + " (we added " + a1 + " and " + a2 + + ")"; + } + } +} +findAttendeesInResults(2); +if (!found1) + throw "FAILED! didn't find attendee1 (" + a1 + ") in results"; +if (!found2) + throw "FAILED! didn't find attendee2 (" + a2 + ") in results"; + +dump("* Removing attendee.\n"); +e.removeAttendee(a1); +if (e.getAttendeeById(a1.id) != null) + throw "FAILED! got back removed attendee " + a1 + " by id"; +findById("myid2", a2); +found1 = false, found2 = false; +findAttendeesInResults(1); +if (found1) + throw "FAILED! found removed attendee " + a1 + " in getAttendees results"; +if (!found2) { + throw "FAILED! 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 "FAILED! didn't find attendee1 (" + a1 + ") in results"; +if (!found2) + throw "FAILED! didn't find attendee2 (" + a2 + ") in results"; + +dump("* Making attendee immutable.\n"); +a1.makeImmutable(); +function testImmutability(a) { + if (a.isMutable) { + throw "FAILED! 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 "FAILED! no error thrown setting " + properties[i] + + "on immutable attendee " + a; + } + if (a[properties[i]] != old) { + throw "FAILED! setting " + properties[i] + " on " + a + + " threw, but changed value anyway!"; + } + } +} + +testImmutability(a1); +dump("* Testing cascaded immutability (event -> attendee).\n"); +e.makeImmutable(); +testImmutability(a2); + +dump("* Testing cloning\n"); +var ec = e.clone(); +var clonedatts = ec.getAttendees({}); +var atts = e.getAttendees({}); +if (atts.length != clonedatts.length) { + throw "FAILED! cloned event has " + clonedatts.length + + "attendees, original had " + atts.length; +} +for (i = 0; i < clonedatts.length; i++) { + if (atts[i] == clonedatts[i]) + throw "FAILED! attendee " + atts[i].id + " shared with clone!"; + if (atts[i].id != clonedatts[i].id) { + throw "FAILED! id mismatch on index " + i + ": " + + atts[i].id + " != " + clonedatts[i].id; + } +} +dump("PASSED!\n"); diff --git a/mozilla/calendar/test/homegrown/misc/ics-roundtrip.js b/mozilla/calendar/test/homegrown/misc/ics-roundtrip.js new file mode 100644 index 00000000000..146447939d2 --- /dev/null +++ b/mozilla/calendar/test/homegrown/misc/ics-roundtrip.js @@ -0,0 +1,41 @@ +var eventClass = C.classes["@mozilla.org/calendar/event;1"]; +var eventIID = C.interfaces.calIEvent; + +dump("* Creating event.\n"); +var e = eventClass.createInstance(eventIID); + +var ics_xmas = +'BEGIN:VCALENDAR\nPRODID:-//ORACLE//NONSGML CSDK 9.0.5 - CalDAVServlet 9.0.5//EN\nVERSION:2.0\nBEGIN:VEVENT\nUID:20041119T052239Z-1000472-1-5c0746bb-Oracle\nORGANIZER;X-ORACLE-GUID=E9359406791C763EE0305794071A39A4;CN=Simon Vaillan\n court:mailto:simon.vaillancourt@oracle.com\nSEQUENCE:0\nDTSTAMP:20041124T010028Z\nCREATED:20041119T052239Z\nX-ORACLE-EVENTINSTANCE-GUID:I1+16778354+1+1+438153759\nX-ORACLE-EVENT-GUID:E1+16778354+1+438153759\nX-ORACLE-EVENTTYPE:DAY EVENT\nTRANSP:TRANSPARENT\nSUMMARY:Christmas\nSTATUS:CONFIRMED\nPRIORITY:0\nDTSTART;VALUE=DATE:20041125\nDTEND;VALUE=DATE:20041125\nCLASS:PUBLIC\nATTENDEE;X-ORACLE-GUID=E92F51FB4A48E91CE0305794071A149C;CUTYPE=INDIVIDUAL\n ;RSVP=TRUE;CN=James Stevens;PARTSTAT=NEEDS-ACTION:mailto:james.stevens@o\n racle.com\nATTENDEE;X-ORACLE-GUID=E9359406791C763EE0305794071A39A4;CUTYPE=INDIVIDUAL\n ;RSVP=FALSE;CN=Simon Vaillancourt;PARTSTAT=ACCEPTED:mailto:simon.vaillan\n court@oracle.com\nATTENDEE;X-ORACLE-GUID=E9359406791D763EE0305794071A39A4;CUTYPE=INDIVIDUAL\n ;RSVP=TRUE;CN=Bernard Desruisseaux;PARTSTAT=NEEDS-ACTION:mailto:bernard.\n desruisseaux@oracle.com\nATTENDEE;X-ORACLE-GUID=E9359406791E763EE0305794071A39A4;CUTYPE=INDIVIDUAL\n ;RSVP=TRUE;CN=Mario Bonin;PARTSTAT=NEEDS-ACTION:mailto:mario.bonin@oracl\n e.com\nATTENDEE;X-ORACLE-GUID=E9359406791F763EE0305794071A39A4;CUTYPE=INDIVIDUAL\n ;RSVP=TRUE;CN=Jeremy Chone;PARTSTAT=NEEDS-ACTION:mailto:jeremy.chone@ora\n cle.com\nATTENDEE;X-ORACLE-PERSONAL-COMMENT-ISDIRTY=TRUE;X-ORACLE-GUID=E9359406792\n 0763EE0305794071A39A4;CUTYPE=INDIVIDUAL;RSVP=TRUE;CN=Mike Shaver;PARTSTA\n T=NEEDS-ACTION:mailto:mike.x.shaver@oracle.com\nATTENDEE;X-ORACLE-GUID=E93594067921763EE0305794071A39A4;CUTYPE=INDIVIDUAL\n ;RSVP=TRUE;CN=David Ball;PARTSTAT=NEEDS-ACTION:mailto:david.ball@oracle.\n com\nATTENDEE;X-ORACLE-GUID=E93594067922763EE0305794071A39A4;CUTYPE=INDIVIDUAL\n ;RSVP=TRUE;CN=Marten Haring;PARTSTAT=NEEDS-ACTION:mailto:marten.den.hari\n ng@oracle.com\nATTENDEE;X-ORACLE-GUID=E93594067923763EE0305794071A39A4;CUTYPE=INDIVIDUAL\n ;RSVP=TRUE;CN=Peter Egyed;PARTSTAT=NEEDS-ACTION:mailto:peter.egyed@oracl\n e.com\nATTENDEE;X-ORACLE-GUID=E93594067924763EE0305794071A39A4;CUTYPE=INDIVIDUAL\n ;RSVP=TRUE;CN=Francois Perrault;PARTSTAT=NEEDS-ACTION:mailto:francois.pe\n rrault@oracle.com\nATTENDEE;X-ORACLE-GUID=E93594067925763EE0305794071A39A4;CUTYPE=INDIVIDUAL\n ;RSVP=TRUE;CN=Vladimir Vukicevic;PARTSTAT=NEEDS-ACTION:mailto:vladimir.v\n ukicevic@oracle.com\nATTENDEE;X-ORACLE-GUID=E93594067926763EE0305794071A39A4;CUTYPE=INDIVIDUAL\n ;RSVP=TRUE;CN=Cyrus Daboo;PARTSTAT=NEEDS-ACTION:mailto:daboo@isamet.com\nATTENDEE;X-ORACLE-GUID=E93594067927763EE0305794071A39A4;CUTYPE=INDIVIDUAL\n ;RSVP=TRUE;CN=Lisa Dusseault;PARTSTAT=NEEDS-ACTION:mailto:lisa@osafounda\n tion.org\nATTENDEE;X-ORACLE-GUID=E93594067928763EE0305794071A39A4;CUTYPE=INDIVIDUAL\n ;RSVP=TRUE;CN=Dan Mosedale;PARTSTAT=NEEDS-ACTION:mailto:dan.mosedale@ora\n cle.com\nATTENDEE;X-ORACLE-GUID=E93594067929763EE0305794071A39A4;CUTYPE=INDIVIDUAL\n ;RSVP=TRUE;CN=Stuart Parmenter;PARTSTAT=NEEDS-ACTION:mailto:stuart.parme\n nter@oracle.com\nEND:VEVENT\nEND:VCALENDAR\n\n'; + +dump("* Setting ical string (xmas)\n"); +e.icalString = ics_xmas; +dump("* Checking basic properties\n"); +var expectedProps = + [["title", "Christmas"], + ["id", "20041119T052239Z-1000472-1-5c0746bb-Oracle"], + ["priority", 0], + ["status", "CONFIRMED"], + ["generation", 0], + ["isAllDay", true]]; +function checkProps(expectedProps, obj) { + for (var i = 0; i < expectedProps.length; i++) { + if (obj[expectedProps[i][0]] != expectedProps[i][1]) { + throw "FAILED! expected " + expectedProps[i][0] + " to be " + + expectedProps[i][1] + " but got " + obj[expectedProps[i][0]]; + } + } +} + +checkProps(expectedProps, e); + +dump("* Checking start date\n"); +expectedProps = + [["month", 10], + ["day", 25], + ["year", 2004], + ["isDate", true]]; +checkProps(expectedProps, e.startDate); +dump("* Checking end date\n"); +checkProps(expectedProps, e.endDate); + +dump("PASSED!\n"); diff --git a/mozilla/calendar/test/homegrown/misc/simple-item-mutability.js b/mozilla/calendar/test/homegrown/misc/simple-item-mutability.js new file mode 100644 index 00000000000..57dce14acf6 --- /dev/null +++ b/mozilla/calendar/test/homegrown/misc/simple-item-mutability.js @@ -0,0 +1,35 @@ +// +// simple test bits +// + + +const eventContractID = "@mozilla.org/calendar/event;1"; +const eventIID = Components.interfaces.calIEvent; + +dump ("Creating mutable event...\n"); +var me = Components.classes[eventContractID].createInstance(eventIID); + +me.title = "Test Title"; +dump ("Title is: " + me.title + " (jsobj: " + me.wrappedJSObject.mTitle + ")\n"); +if (me.title != "Test Title") { + throw("FAILED! Title on mutable event contained unexpected value."); +} + +dump ("Setting event-to be non-mutable...\n"); +me.makeImmutable(); + +dump ("Trying to set title (should fail)\n"); +try { + // this should cause an exception + me.title = "Fail"; + + // so we'll only get here if something is wrong, and there's no exception + dump("FAILED\n!"); +} catch (ex) { +} + +if (me.title != "Test Title") { + throw("FAILED! Title on immutable event contained unexpected value: " + + me.title); +} + diff --git a/mozilla/calendar/test/homegrown/misc/synchronization.js b/mozilla/calendar/test/homegrown/misc/synchronization.js new file mode 100644 index 00000000000..73a534c7db3 --- /dev/null +++ b/mozilla/calendar/test/homegrown/misc/synchronization.js @@ -0,0 +1,192 @@ +/* + * This is the memory hog version. Read all events in memory, then sync + * from there. + * Doing it the right async way gives me too many headaches. + */ + +const calICalendar = Components.interfaces.calICalendar; + +var emptyListener = +{ + onOperationComplete: function(aCalendar, aStatus, aOperationType, aId, aDetail) {}, + onGetResult: function(aCalendar, aStatus, aItemType, aDetail, aCount, aItems) {} +}; + +var localcal = Components.classes["@mozilla.org/calendar/calendar;1?type=memory"] + .createInstance(Components.interfaces.calICalendar); +var remotecal = Components.classes["@mozilla.org/calendar/calendar;1?type=memory"] + .createInstance(Components.interfaces.calICalendar); +var changecal = Components.classes["@mozilla.org/calendar/calendar;1?type=memory"] + .createInstance(Components.interfaces.calICalendar); + + +// local: B CC +// change: A, B, C +// remote: A, C +// expected: B, CC +createEvent("i2", "B", localcal); +createEvent("i3", "CC", localcal); +createEvent("i1", "A", remotecal); +createEvent("i3", "C", remotecal); +createEvent("i1", "A", changecal); +createEvent("i2", "B", changecal); +createEvent("i3", "C", changecal); + +dump("Before\n"); +dumpCals(); + +// Start by getting all the items into an array +var localItems = []; +var remoteItems = []; +var changeItems = []; + +// This will get the items from the calendars into the global arrays, +// then call doSync() +getCalandarItems(); + +function doSync() +{ + /* + * forall changeEvents + * if (!remoteEvent) + * remoteCalendar.add(localEvent); + * else if (remoteEvent != changedEvent) + * conflict(); + * else if (!localEvent) + * remoteCalendar.deleteEvent(changedEvent.id) + */ + + for (id in changeItems) { + if (!remoteItems[id]) + remotecal.addItem(localItems[id].clone(), emptyListener); + else if (!itemsAreEqual(remoteItems[id], changeItems[id])) + dump("Conflict! wheep! "+remoteItems[id].title+" != "+changeItems[id].title+"\n"); + else if (!localItems[id]) { + remotecal.deleteItem(remoteItems[id], emptyListener); + delete remoteItems[id]; + } + } + + //dump("Halfway\n"); + //dumpCals(); + + // now for part two: remote to local + + /* + * forall remoteEvents + * if (!localEvent) + * localCalendar.add(remoteEvent); + * else if (localEvent != remoteEvent) + * if (!changeEvent) + * localCalendar.modify(localEvent.id, remoteEvent); + * else if (changeEvent == remoteEvent) + * remoteCalendar.modify(remoteEvent.id, localEvent); + * else + * conflict(); + */ + + for (id in remoteItems) { + if (!localItems[id]) + localcal.addItem(remoteItems[i].clone(), emptyListener); + if (!itemsAreEqual(localItems[id], remoteItems[id])) { + if (!changeItems[id]) { + copyItems(remoteItems[id], localItems[id]); + localcal.modifyItem(localItems[id], emptyListener); + } else if (itemsAreEqual(remoteItems[id], changeItems[id])) { + copyItems(localItems[id], remoteItems[id]); + remotecal.modifyItem(remoteItems[id], emptyListener); + } else { + // There is a conflict, but that was already detected before when + // dealing with locally changed items. No need to do that again. + //dump("Conflict\n"); + } + + } + } + + dump("After\n"); + dumpCals(); +} + + +function itemsAreEqual(itemA, itemB) +{ + return (itemA.id == itemB.id && itemA.title == itemB.title) +} + +function copyItems(aSource, aDest) +{ + aDest.title = aSource.title; +} + +function createEvent(aID, aTitle, aCal) +{ + var event = Components.classes["@mozilla.org/calendar/event;1"] + .createInstance(Components.interfaces.calIEvent); + event.title = aTitle; + event.id = aID; + aCal.addItem(event, emptyListener); +} + +function getCalandarItems() +{ + var calendarsFinished = 0; + + var getListener = + { + onOperationComplete: function(aCalendar, aStatus, aOperationType, aId, aDetail) + { + calendarsFinished++; + if (calendarsFinished == 3) { + doSync(); + } + }, + onGetResult: function(aCalendar, aStatus, aItemType, aDetail, aCount, aItems) + { + if (aCount) { + var ar; + if (aCalendar == localcal) + items = localItems; + else if (aCalendar == remotecal) + items = remoteItems; + else if (aCalendar == changecal) + items = changeItems; + + for (var i=0; i + * Mike Shaver + * + * 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 ***** */ + +const C = Components; +const CI = C.interfaces; + +const evQSvc = getService("@mozilla.org/event-queue-service;1", + "nsIEventQueueService"); +const evQ = evQSvc.getSpecialEventQueue(CI.nsIEventQueueService.CURRENT_THREAD_EVENT_QUEUE); + +var done = false; + +function runEventPump() +{ + pumpRunning = true; + while (pumpRunning) { + evQ.processPendingEvents(); + } +} + +function stopEventPump() +{ + pumpRunning = false; +} + +// I wonder how many copies of this are floating around +function findErr(result) +{ + for (var i in C.results) { + if (C.results[i] == result) { + return i; + } + } + dump("No result code found for " + result + "\n"); +} +// I wonder how many copies of this are floating around +function findIface(iface) +{ + for (var i in CI) { + if (iface.equals(CI[i])) { + return i; + } + } + dump("No interface found for " + iface + "\n"); +} + +function findOpName(op) +{ + for (var i in CI.calIOperationListener) { + if (op == CI.calIOperationListener[i]) { + return i; + } + } + dump("Operation type " + op + "unknown\n"); +} + +function getService(contract, iface) +{ + return C.classes[contract].getService(CI[iface]); +} + +function createInstance(contract, iface) +{ + return C.classes[contract].createInstance(CI[iface]); +} + +function calOpListener() { +} + +calOpListener.prototype = +{ + + onOperationComplete: function(aCalendar, aStatus, aOperationType, aId, + aDetail) { + dump("onOperationComplete:\n\t"); + dump(aCalendar + "\n\t" + findErr(aStatus) + "\n\t" + + findOpName(aOperationType) + "\n\t" + aId + "\n\t" + aDetail + + "\n"); + + stopEventPump(); + done = true; + + if (Components.isSuccessCode(aStatus)) { + dump("PASSED! Listener returned failure code.\n"); + } else { + dump("FAILED! Listener returned failure code.\n"); + } + }, + + onGetResult: function(aCalendar, aStatus, aItemType, aDetail, aCount, + aItems) { + dump("onGetResult: \n\t"); + dump(aCalendar + "\n\t" + findErr(aStatus) + "\n\t" + findIface(aItemType) + + "\n\t" + aDetail + "\n\t" + aCount + "\n\t" + aItems + "\n"); + } +} + +function GETITEM(aId) { + +} + +const ioSvc = getService("@mozilla.org/network/io-service;1", + "nsIIOService"); + +function URLFromSpec(spec) +{ + return ioSvc.newURI(spec, null, null); +} + diff --git a/mozilla/calendar/test/jsDriver.pl b/mozilla/calendar/test/jsDriver.pl new file mode 100755 index 00000000000..2249551e4a1 --- /dev/null +++ b/mozilla/calendar/test/jsDriver.pl @@ -0,0 +1,1289 @@ +#!/usr/bin/perl +# +# The contents of this file are subject to the Netscape 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/NPL/ +# +# 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 JavaScript Core Tests. +# +# The Initial Developer of the Original Code is Netscape +# Communications Corporation. Portions created by Netscape are +# Copyright (C) 1997-1999 Netscape Communications Corporation. All +# Rights Reserved. +# +# Alternatively, the contents of this file may be used under the +# terms of the GNU Public License (the "GPL"), in which case the +# provisions of the GPL are applicable instead of those above. +# If you wish to allow use of your version of this file only +# under the terms of the GPL and not to allow others to use your +# version of this file under the NPL, indicate your decision by +# deleting the provisions above and replace them with the notice +# and other provisions required by the GPL. If you do not delete +# the provisions above, a recipient may use your version of this +# file under either the NPL or the GPL. +# +# Contributers: +# Robert Ginda +# +# Second cut at runtests.pl script originally by +# Christine Begle (cbegle@netscape.com) +# Branched 11/01/99 +# + +use strict; +use Getopt::Mixed "nextOption"; + +my $os_type = &get_os_type; +my $unixish = (($os_type ne "WIN") && ($os_type ne "MAC")); +my $path_sep = ($os_type eq "MAC") ? ":" : "/"; +my $win_sep = ($os_type eq "WIN")? &get_win_sep : ""; +my $redirect_command = ($os_type ne "MAC") ? " 2>&1" : ""; + +# command line option defaults +my $opt_suite_path; +my $opt_trace = 0; +my $opt_classpath = ""; +my $opt_rhino_opt = 0; +my $opt_rhino_ms = 0; +my @opt_engine_list; +my $opt_engine_type = ""; +my $opt_engine_params = ""; +my $opt_user_output_file = 0; +my $opt_output_file = ""; +my @opt_test_list_files; +my @opt_neg_list_files; +my $opt_shell_path = ""; +my $opt_java_path = ""; +my $opt_bug_url = "http://bugzilla.mozilla.org/show_bug.cgi?id="; +my $opt_console_failures = 0; +my $opt_lxr_url = "http://lxr.mozilla.org/mozilla/source/js/tests/"; +my $opt_exit_munge = ($os_type ne "MAC") ? 1 : 0; + +# command line option definition +my $options = "b=s bugurl>b c=s classpath>c e=s engine>e f=s file>f " . + "h help>h i j=s javapath>j k confail>k l=s list>l L=s neglist>L " . + "o=s opt>o p=s testpath>p s=s shellpath>s t trace>t u=s lxrurl>u " . + "x noexitmunge>x"; + +if ($os_type eq "MAC") { + $opt_suite_path = `directory`; + $opt_suite_path =~ s/[\n\r]//g; + $opt_suite_path .= ":"; +} else { + $opt_suite_path = "./"; +} + +&parse_args; + +my $user_exit = 0; +my ($engine_command, $html, $failures_reported, $tests_completed, + $exec_time_string); +my @failed_tests; +my @test_list = &get_test_list; + +if ($#test_list == -1) { + die ("Nothing to test.\n"); +} + +if ($unixish) { + # on unix, ^C pauses the tests, and gives the user a chance to quit but + # report on what has been done, to just quit, or to continue (the + # interrupted test will still be skipped.) + # windows doesn't handle the int handler they way we want it to, + # so don't even pretend to let the user continue. + $SIG{INT} = 'int_handler'; +} + +&main; + +#End. + +sub main { + my $start_time; + + while ($opt_engine_type = pop (@opt_engine_list)) { + dd ("Testing engine '$opt_engine_type'"); + + $engine_command = &get_engine_command; + $html = ""; + @failed_tests = (); + $failures_reported = 0; + $tests_completed = 0; + $start_time = time; + + + &execute_tests (@test_list); + + my $exec_time = (time - $start_time); + my $exec_hours = int($exec_time / 60 / 60); + $exec_time -= $exec_hours * 60 * 60; + my $exec_mins = int($exec_time / 60); + $exec_time -= $exec_mins * 60; + my $exec_secs = ($exec_time % 60); + + if ($exec_hours > 0) { + $exec_time_string = "$exec_hours hours, $exec_mins minutes, " . + "$exec_secs seconds"; + } elsif ($exec_mins > 0) { + $exec_time_string = "$exec_mins minutes, $exec_secs seconds"; + } else { + $exec_time_string = "$exec_secs seconds"; + } + + if (!$opt_user_output_file) { + $opt_output_file = &get_tempfile_name; + } + + &write_results; + + } +} + +sub execute_tests { + my (@test_list) = @_; + my ($test, $shell_command, $line, @output, $path); + my $file_param = " -f "; + my ($last_suite, $last_test_dir); + + &status ("Executing " . ($#test_list + 1) . " test(s)."); + + foreach $test (@test_list) { + my ($suite, $test_dir, $test_file) = split($path_sep, $test); + # *-n.js is a negative test, expect exit code 3 (runtime error) + my $expected_exit = ($test =~ /\-n\.js$/) ? 3 : 0; + my ($got_exit, $exit_signal); + my $failure_lines; + my $bug_number; + my $status_lines; + + # user selected [Q]uit from ^C handler. + if ($user_exit) { + return; + } + + # Append the shell.js files to the shell_command if they're there. + # (only check for their existance if the suite or test_dir has changed + # since the last time we looked.) + if ($last_suite ne $suite || $last_test_dir ne $test_dir) { + $shell_command = &xp_path($engine_command); + + $path = &xp_path($opt_suite_path . $suite . "/shell.js"); + if (-f $path) { + $shell_command .= $file_param . $path; + } + + $path = &xp_path($opt_suite_path . $suite . "/" . + $test_dir . "/shell.js"); + if (-f $path) { + $shell_command .= $file_param . $path; + } + + $last_suite = $suite; + $last_test_dir = $test_dir; + } + + $path = &xp_path($opt_suite_path . $test); + &dd ("executing: " . $shell_command . $file_param . $path); + + open (OUTPUT, $shell_command . $file_param . $path . + $redirect_command . " |"); + @output = ; + close (OUTPUT); + + @output = grep (!/js\>/, @output); + + if ($opt_exit_munge == 1) { + # signal information in the lower 8 bits, exit code above that + $got_exit = ($? >> 8); + $exit_signal = ($? & 255); + } else { + # user says not to munge the exit code + $got_exit = $?; + $exit_signal = 0; + } + + $failure_lines = ""; + $bug_number = ""; + $status_lines = ""; + + foreach $line (@output) { + + # watch for testcase to proclaim what exit code it expects to + # produce (0 by default) + if ($line =~ /expect(ed)?\s*exit\s*code\s*\:?\s*(\d+)/i) { + $expected_exit = $2; + &dd ("Test case expects exit code $expected_exit"); + } + + # watch for failures + if ($line =~ /failed!/i) { + $failure_lines .= $line; + } + + # and watch for bugnumbers + # XXX This only allows 1 bugnumber per testfile, should be + # XXX modified to allow for multiple. + if ($line =~ /bugnumber\s*\:?\s*(.*)/i) { + $1 =~ /(\n+)/; + $bug_number = $1; + } + + # and watch for status + if ($line =~ /status/i) { + $status_lines .= $line; + } + + } + + if (!@output) { + @output = ("Testcase produced no output!"); + } + + if ($got_exit != $expected_exit) { + # full testcase output dumped on mismatched exit codes, + &report_failure ($test, "Expected exit code " . + "$expected_exit, got $got_exit\n" . + "Testcase terminated with signal $exit_signal\n" . + "Complete testcase output was:\n" . + join ("\n",@output), $bug_number); + } elsif ($failure_lines) { + # only offending lines if exit codes matched + &report_failure ($test, "$status_lines\n". + "Failure messages were:\n$failure_lines", + $bug_number); + } + + &dd ("exit code $got_exit, exit signal $exit_signal."); + + $tests_completed++; + } +} + +sub write_results { + my ($list_name, $neglist_name); + my $completion_date = localtime; + my $failure_pct = int(($failures_reported / $tests_completed) * 10000) / + 100; + &dd ("Writing output to $opt_output_file."); + + if ($#opt_test_list_files == -1) { + $list_name = "All tests"; + } elsif ($#opt_test_list_files < 10) { + $list_name = join (", ", @opt_test_list_files); + } else { + $list_name = "($#opt_test_list_files test files specified)"; + } + + if ($#opt_neg_list_files == -1) { + $neglist_name = "(none)"; + } elsif ($#opt_test_list_files < 10) { + $neglist_name = join (", ", @opt_neg_list_files); + } else { + $neglist_name = "($#opt_neg_list_files skip files specified)"; + } + + open (OUTPUT, "> $opt_output_file") || + die ("Could not create output file $opt_output_file"); + + print OUTPUT + ("\n" . + "Test results, $opt_engine_type\n" . + "\n" . + "\n" . + "\n" . + "

Test results, $opt_engine_type


\n" . + "

\n" . + "Test List: $list_name
\n" . + "Skip List: $neglist_name
\n" . + ($#test_list + 1) . " test(s) selected, $tests_completed test(s) " . + "completed, $failures_reported failures reported " . + "($failure_pct% failed)
\n" . + "Engine command line: $engine_command
\n" . + "OS type: $os_type
\n"); + + if ($opt_engine_type =~ /^rhino/) { + open (JAVAOUTPUT, $opt_java_path . "java -fullversion " . + $redirect_command . " |"); + print OUTPUT ; + print OUTPUT "
"; + close (JAVAOUTPUT); + } + + print OUTPUT + ("Testcase execution time: $exec_time_string.
\n" . + "Tests completed on $completion_date.

\n"); + + if ($failures_reported > 0) { + print OUTPUT + ("[ Failure Details | " . + "Retest List | " . + "Test Selection Page ]
\n" . + "


\n" . + "\n" . + "

Failure Details


\n
" . + $html . + "
\n[ Top of Page | " . + "Top of Failures ]
\n" . + "
\n" . + "\n" . + "

Retest List


\n" . + "
\n" .
+           "# Retest List, $opt_engine_type, " .
+           "generated $completion_date.\n" .
+           "# Original test base was: $list_name.\n" .
+           "# $tests_completed of " . ($#test_list + 1) .
+           " test(s) were completed, " .
+           "$failures_reported failures reported.\n" .
+           join ("\n", @failed_tests) .
+           "
\n" . + "[ Top of Page | " . + "Top of Retest List ]
\n"); + } else { + print OUTPUT + ("

Whoop-de-doo, nothing failed!

\n"); + } + + print OUTPUT ""; + + close (OUTPUT); + + &status ("Wrote results to '$opt_output_file'."); + + if ($opt_console_failures) { + &status ("$failures_reported test(s) failed"); + } + +} + +sub parse_args { + my ($option, $value, $lastopt); + + &dd ("checking command line options."); + + Getopt::Mixed::init ($options); + $Getopt::Mixed::order = $Getopt::Mixed::RETURN_IN_ORDER; + + while (($option, $value) = nextOption()) { + + if ($option eq "b") { + &dd ("opt: setting bugurl to '$value'."); + $opt_bug_url = $value; + + } elsif ($option eq "c") { + &dd ("opt: setting classpath to '$value'."); + $opt_classpath = $value; + + } elsif (($option eq "e") || (($option eq "") && ($lastopt eq "e"))) { + &dd ("opt: adding engine $value."); + push (@opt_engine_list, $value); + + } elsif ($option eq "f") { + if (!$value) { + die ("Output file cannot be null.\n"); + } + &dd ("opt: setting output file to '$value'."); + $opt_user_output_file = 1; + $opt_output_file = $value; + + } elsif ($option eq "h") { + &usage; + + } elsif ($option eq "j") { + if (!($value =~ /[\/\\]$/)) { + $value .= "/"; + } + &dd ("opt: setting java path to '$value'."); + $opt_java_path = $value; + + } elsif ($option eq "k") { + &dd ("opt: displaying failures on console."); + $opt_console_failures=1; + + } elsif ($option eq "l" || (($option eq "") && ($lastopt eq "l"))) { + $option = "l"; + &dd ("opt: adding test list '$value'."); + push (@opt_test_list_files, $value); + + } elsif ($option eq "L" || (($option eq "") && ($lastopt eq "L"))) { + $option = "L"; + &dd ("opt: adding negative list '$value'."); + push (@opt_neg_list_files, $value); + + } elsif ($option eq "o") { + $opt_engine_params = $value; + &dd ("opt: setting engine params to '$opt_engine_params'."); + + } elsif ($option eq "p") { + $opt_suite_path = $value; + + if ($os_type eq "MAC") { + if (!($opt_suite_path =~ /\:$/)) { + $opt_suite_path .= ":"; + } + } else { + if (!($opt_suite_path =~ /[\/\\]$/)) { + $opt_suite_path .= "/"; + } + } + + &dd ("opt: setting suite path to '$opt_suite_path'."); + + } elsif ($option eq "s") { + $opt_shell_path = $value; + &dd ("opt: setting shell path to '$opt_shell_path'."); + + } elsif ($option eq "t") { + &dd ("opt: tracing output. (console failures at no extra charge.)"); + $opt_console_failures = 1; + $opt_trace = 1; + + } elsif ($option eq "u") { + &dd ("opt: setting lxr url to '$value'."); + $opt_lxr_url = $value; + + } elsif ($option eq "x") { + &dd ("opt: turning off exit munging."); + $opt_exit_munge = 0; + + } else { + &usage; + } + + $lastopt = $option; + + } + + Getopt::Mixed::cleanup(); + + if ($#opt_engine_list == -1) { + die "You must select a shell to test in.\n"; + } + +} + +# +# print the arguments that this script expects +# +sub usage { + print STDERR + ("\nusage: $0 [] \n" . + "(-b|--bugurl) Bugzilla URL.\n" . + " (default is $opt_bug_url)\n" . + "(-c|--classpath) Classpath (Rhino only.)\n" . + "(-e|--engine) ... Specify the type of engine(s) to test.\n" . + " is one or more of\n" . + " (smopt|smdebug|lcopt|lcdebug|xpcshell|" . + "rhino|rhinoi|rhinoms|rhinomsi|rhino9|rhinoms9).\n" . + "(-f|--file) Redirect output to file named .\n" . + " (default is " . + "results--.html)\n" . + "(-h|--help) Print this message.\n" . + "(-j|--javapath) Location of java executable.\n" . + "(-k|--confail) Log failures to console (also.)\n" . + "(-l|--list) ... List of tests to execute.\n" . + "(-L|--neglist) ... List of tests to skip.\n" . + "(-o|--opt) Options to pass to the JavaScript engine.\n" . + " (Make sure to quote them!)\n" . + "(-p|--testpath) Root of the test suite. (default is ./)\n" . + "(-s|--shellpath) Location of JavaScript shell.\n" . + "(-t|--trace) Trace script execution.\n" . + "(-u|--lxrurl) Complete URL to tests subdirectory on lxr.\n" . + " (default is $opt_lxr_url)\n" . + "(-x|--noexitmunge) Don't do exit code munging (try this if it\n" . + " seems like your exit codes are turning up\n" . + " as exit signals.)\n"); + exit (1); + +} + +# +# get the shell command used to start the (either) engine +# +sub get_engine_command { + + my $retval; + + if ($opt_engine_type eq "rhino") { + &dd ("getting rhino engine command."); + $opt_rhino_opt = 0; + $opt_rhino_ms = 0; + $retval = &get_rhino_engine_command; + } elsif ($opt_engine_type eq "rhinoi") { + &dd ("getting rhinoi engine command."); + $opt_rhino_opt = -1; + $opt_rhino_ms = 0; + $retval = &get_rhino_engine_command; + } elsif ($opt_engine_type eq "rhino9") { + &dd ("getting rhino engine command."); + $opt_rhino_opt = 9; + $opt_rhino_ms = 0; + $retval = &get_rhino_engine_command; + } elsif ($opt_engine_type eq "rhinoms") { + &dd ("getting rhinoms engine command."); + $opt_rhino_opt = 0; + $opt_rhino_ms = 1; + $retval = &get_rhino_engine_command; + } elsif ($opt_engine_type eq "rhinomsi") { + &dd ("getting rhinomsi engine command."); + $opt_rhino_opt = -1; + $opt_rhino_ms = 1; + $retval = &get_rhino_engine_command; + } elsif ($opt_engine_type eq "rhinoms9") { + &dd ("getting rhinomsi engine command."); + $opt_rhino_opt = 9; + $opt_rhino_ms = 1; + $retval = &get_rhino_engine_command; + } elsif ($opt_engine_type eq "xpcshell") { + &dd ("getting xpcshell engine command."); + $retval = &get_xpc_engine_command; + } elsif ($opt_engine_type =~ /^lc(opt|debug)$/) { + &dd ("getting liveconnect engine command."); + $retval = &get_lc_engine_command; + } elsif ($opt_engine_type =~ /^sm(opt|debug)$/) { + &dd ("getting spidermonkey engine command."); + $retval = &get_sm_engine_command; + } elsif ($opt_engine_type =~ /^ep(opt|debug)$/) { + &dd ("getting epimetheus engine command."); + $retval = &get_ep_engine_command; + } else { + die ("Unknown engine type selected, '$opt_engine_type'.\n"); + } + + $retval .= " $opt_engine_params"; + + &dd ("got '$retval'"); + + return $retval; + +} + +# +# get the shell command used to run rhino +# +sub get_rhino_engine_command { + my $retval = $opt_java_path . ($opt_rhino_ms ? "jview " : "java "); + + if ($opt_shell_path) { + $opt_classpath = ($opt_classpath) ? + $opt_classpath . ":" . $opt_shell_path : + $opt_shell_path; + } + + if ($opt_classpath) { + $retval .= ($opt_rhino_ms ? "/cp:p" : "-classpath") . " $opt_classpath "; + } + + $retval .= "org.mozilla.javascript.tools.shell.Main"; + + if ($opt_rhino_opt) { + $retval .= " -opt $opt_rhino_opt"; + } + + return $retval; + +} + +# +# get the shell command used to run xpcshell +# +sub get_xpc_engine_command { + my $retval; + my $m5_home = @ENV{"MOZILLA_FIVE_HOME"} || + die ("You must set MOZILLA_FIVE_HOME to use the xpcshell" , + (!$unixish) ? "." : ", also " . + "setting LD_LIBRARY_PATH to the same directory may get rid of " . + "any 'library not found' errors.\n"); + + if (($unixish) && (!@ENV{"LD_LIBRARY_PATH"})) { + print STDERR "-#- WARNING: LD_LIBRARY_PATH is not set, xpcshell may " . + "not be able to find the required components.\n"; + } + + if (!($m5_home =~ /[\/\\]$/)) { + $m5_home .= "/"; + } + + $retval = $m5_home . "xpcshell"; + + if ($os_type eq "WIN") { + $retval .= ".exe"; + } + + $retval = &xp_path($retval); + + if (($os_type ne "MAC") && !(-x $retval)) { + # mac doesn't seem to deal with -x correctly + die ($retval . " is not a valid executable on this system.\n"); + } + + return $retval; + +} + +# +# get the shell command used to run spidermonkey +# +sub get_sm_engine_command { + my $retval; + + # Look for Makefile.ref style make first. + # (On Windows, spidermonkey can be made by two makefiles, each putting the + # executable in a diferent directory, under a different name.) + + if ($opt_shell_path) { + # if the user provided a path to the shell, return that. + $retval = $opt_shell_path; + + } else { + + if ($os_type eq "MAC") { + $retval = $opt_suite_path . ":src:macbuild:JS"; + } else { + $retval = $opt_suite_path . "../src/"; + opendir (SRC_DIR_FILES, $retval); + my @src_dir_files = readdir(SRC_DIR_FILES); + closedir (SRC_DIR_FILES); + + my ($dir, $object_dir); + my $pattern = ($opt_engine_type eq "smdebug") ? + 'DBG.OBJ' : 'OPT.OBJ'; + + # scan for the first directory matching + # the pattern expected to hold this type (debug or opt) of engine + foreach $dir (@src_dir_files) { + if ($dir =~ $pattern) { + $object_dir = $dir; + last; + } + } + + if (!$object_dir && $os_type ne "WIN") { + die ("Could not locate an object directory in $retval " . + "matching the pattern *$pattern. Have you built the " . + "engine?\n"); + } + + if (!(-x $retval . $object_dir . "/js.exe") && ($os_type eq "WIN")) { + # On windows, you can build with js.mak as well as Makefile.ref + # (Can you say WTF boys and girls? I knew you could.) + # So, if the exe the would have been built by Makefile.ref isn't + # here, check for the js.mak version before dying. + if ($opt_shell_path) { + $retval = $opt_shell_path; + if (!($retval =~ /[\/\\]$/)) { + $retval .= "/"; + } + } else { + if ($opt_engine_type eq "smopt") { + $retval = "../src/Release/"; + } else { + $retval = "../src/Debug/"; + } + } + + $retval .= "jsshell.exe"; + + } else { + $retval .= $object_dir . "/js"; + if ($os_type eq "WIN") { + $retval .= ".exe"; + } + } + } # mac/ not mac + + $retval = &xp_path($retval); + + } # (user provided a path) + + + if (($os_type ne "MAC") && !(-x $retval)) { + # mac doesn't seem to deal with -x correctly + die ($retval . " is not a valid executable on this system.\n"); + } + + return $retval; + +} + +# +# get the shell command used to run epimetheus +# +sub get_ep_engine_command { + my $retval; + + if ($opt_shell_path) { + # if the user provided a path to the shell, return that - + $retval = $opt_shell_path; + + } else { + my $dir; + my $os; + my $debug; + my $opt; + my $exe; + + $dir = $opt_suite_path . "../../js2/src/"; + + if ($os_type eq "MAC") { + # + # On the Mac, the debug and opt builds lie in the same directory - + # + $os = "macbuild:"; + $debug = ""; + $opt = ""; + $exe = "JS2"; + } elsif ($os_type eq "WIN") { + $os = "winbuild/Epimetheus/"; + $debug = "Debug/"; + $opt = "Release/"; + $exe = "Epimetheus.exe"; + } else { + $os = ""; + $debug = ""; + $opt = ""; # <<<----- XXX THIS IS NOT RIGHT! CHANGE IT! + $exe = "epimetheus"; + } + + + if ($opt_engine_type eq "epdebug") { + $retval = $dir . $os . $debug . $exe; + } else { + $retval = $dir . $os . $opt . $exe; + } + + $retval = &xp_path($retval); + + }# (user provided a path) + + + if (($os_type ne "MAC") && !(-x $retval)) { + # mac doesn't seem to deal with -x correctly + die ($retval . " is not a valid executable on this system.\n"); + } + + return $retval; +} + +# +# get the shell command used to run the liveconnect shell +# +sub get_lc_engine_command { + my $retval; + + if ($opt_shell_path) { + $retval = $opt_shell_path; + } else { + if ($os_type eq "MAC") { + die "Don't know how to run the lc shell on the mac yet.\n"; + } else { + $retval = $opt_suite_path . "../src/liveconnect/"; + opendir (SRC_DIR_FILES, $retval); + my @src_dir_files = readdir(SRC_DIR_FILES); + closedir (SRC_DIR_FILES); + + my ($dir, $object_dir); + my $pattern = ($opt_engine_type eq "lcdebug") ? + 'DBG.OBJ' : 'OPT.OBJ'; + + foreach $dir (@src_dir_files) { + if ($dir =~ $pattern) { + $object_dir = $dir; + last; + } + } + + if (!$object_dir) { + die ("Could not locate an object directory in $retval " . + "matching the pattern *$pattern. Have you built the " . + "engine?\n"); + } + + $retval .= $object_dir . "/"; + + if ($os_type eq "WIN") { + $retval .= "lcshell.exe"; + } else { + $retval .= "lcshell"; + } + } # mac/ not mac + + $retval = &xp_path($retval); + + } # (user provided a path) + + + if (($os_type ne "MAC") && !(-x $retval)) { + # mac doesn't seem to deal with -x correctly + die ("$retval is not a valid executable on this system.\n"); + } + + return $retval; + +} + +sub get_os_type { + + if ("\n" eq "\015") { + return "MAC"; + } + + my $uname = `uname -a`; + + if ($uname =~ /WIN/) { + $uname = "WIN"; + } else { + chop $uname; + } + + &dd ("get_os_type returning '$uname'."); + return $uname; + +} + +sub get_test_list { + my @test_list; + my @neg_list; + + if ($#opt_test_list_files > -1) { + my $list_file; + + &dd ("getting test list from user specified source."); + + foreach $list_file (@opt_test_list_files) { + push (@test_list, &expand_user_test_list($list_file)); + } + } else { + &dd ("no list file, groveling in '$opt_suite_path'."); + + @test_list = &get_default_test_list($opt_suite_path); + } + + if ($#opt_neg_list_files > -1) { + my $list_file; + my $orig_size = $#test_list + 1; + my $actually_skipped; + + &dd ("getting negative list from user specified source."); + + foreach $list_file (@opt_neg_list_files) { + push (@neg_list, &expand_user_test_list($list_file)); + } + + @test_list = &subtract_arrays (\@test_list, \@neg_list); + + $actually_skipped = $orig_size - ($#test_list + 1); + + &dd ($actually_skipped . " of " . $orig_size . + " tests will be skipped."); + &dd ((($#neg_list + 1) - $actually_skipped) . " skip tests were " . + "not actually part of the test list."); + + } + + + # Don't run any shell.js files as tests; they are only utility files + @test_list = grep (!/shell.*\.js$/, @test_list); + + return @test_list; + +} + +# +# reads $list_file, storing non-comment lines into an array. +# lines in the form suite_dir/[*] or suite_dir/test_dir/[*] are expanded +# to include all test files under the specified directory +# +sub expand_user_test_list { + my ($list_file) = @_; + my @retval = (); + + # + # Trim off the leading path separator that begins relative paths on the Mac. + # Each path will get concatenated with $opt_suite_path, which ends in one. + # + # Also note: + # + # We will call expand_test_list_entry(), which does pattern-matching on $list_file. + # This will make the pattern-matching the same as it would be on Linux/Windows - + # + if ($os_type eq "MAC") { + $list_file =~ s/^$path_sep//; + } + + if ($list_file =~ /\.js$/ || -d $opt_suite_path . $list_file) { + + push (@retval, &expand_test_list_entry($list_file)); + + } else { + + open (TESTLIST, $list_file) || + die("Error opening test list file '$list_file': $!\n"); + + while () { + s/\r*\n*$//; + if (!(/\s*\#/)) { + # It's not a comment, so process it + push (@retval, &expand_test_list_entry($_)); + } + } + + close (TESTLIST); + + } + + return @retval; + +} + + +# +# Currently expect all paths to be RELATIVE to the top-level tests directory. +# One day, this should be improved to allow absolute paths as well - +# +sub expand_test_list_entry { + my ($entry) = @_; + my @retval; + + if ($entry =~ /\.js$/) { + # it's a regular entry, add it to the list + if (-f $opt_suite_path . $entry) { + push (@retval, $entry); + } else { + status ("testcase '$entry' not found."); + } + } elsif ($entry =~ /(.*$path_sep[^\*][^$path_sep]*)$path_sep?\*?$/) { + # Entry is in the form suite_dir/test_dir[/*] + # so iterate all tests under it + my $suite_and_test_dir = $1; + my @test_files = &get_js_files ($opt_suite_path . + $suite_and_test_dir); + my $i; + + foreach $i (0 .. $#test_files) { + $test_files[$i] = $suite_and_test_dir . $path_sep . + $test_files[$i]; + } + + splice (@retval, $#retval + 1, 0, @test_files); + + } elsif ($entry =~ /([^\*][^$path_sep]*)$path_sep?\*?$/) { + # Entry is in the form suite_dir[/*] + # so iterate all test dirs and tests under it + my $suite = $1; + my @test_dirs = &get_subdirs ($opt_suite_path . $suite); + my $test_dir; + + foreach $test_dir (@test_dirs) { + my @test_files = &get_js_files ($opt_suite_path . $suite . + $path_sep . $test_dir); + my $i; + + foreach $i (0 .. $#test_files) { + $test_files[$i] = $suite . $path_sep . $test_dir . $path_sep . + $test_files[$i]; + } + + splice (@retval, $#retval + 1, 0, @test_files); + } + + } else { + die ("Dont know what to do with list entry '$entry'.\n"); + } + + return @retval; + +} + +# +# Grovels through $suite_path, searching for *all* test files. Used when the +# user doesn't supply a test list. +# +sub get_default_test_list { + my ($suite_path) = @_; + my @suite_list = &get_subdirs($suite_path); + my $suite; + my @retval; + + foreach $suite (@suite_list) { + my @test_dir_list = get_subdirs ($suite_path . $suite); + my $test_dir; + + foreach $test_dir (@test_dir_list) { + my @test_list = get_js_files ($suite_path . $suite . $path_sep . + $test_dir); + my $test; + + foreach $test (@test_list) { + $retval[$#retval + 1] = $suite . $path_sep . $test_dir . + $path_sep . $test; + } + } + } + + return @retval; + +} + +# +# generate an output file name based on the date +# +sub get_tempfile_name { + my ($sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdst) = + &get_padded_time (localtime); + my $rv; + + if ($os_type ne "MAC") { + $rv = "results-" . $year . "-" . $mon . "-" . $mday . "-" . $hour . + $min . $sec . "-" . $opt_engine_type; + } else { + $rv = "res-" . $year . $mon . $mday . $hour . $min . $sec . "-" . + $opt_engine_type + } + + return $rv . ".html"; +} + +sub get_padded_time { + my ($sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdst) = @_; + + $mon++; + $mon = &zero_pad($mon); + $year += 1900; + $mday= &zero_pad($mday); + $sec = &zero_pad($sec); + $min = &zero_pad($min); + $hour = &zero_pad($hour); + + return ($sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdst); + +} + +sub zero_pad { + my ($string) = @_; + + $string = ($string < 10) ? "0" . $string : $string; + return $string; +} + +sub subtract_arrays { + my ($whole_ref, $part_ref) = @_; + my @whole = @$whole_ref; + my @part = @$part_ref; + my $line; + + foreach $line (@part) { + @whole = grep (!/$line/, @whole); + } + + return @whole; + +} + +# +# Convert unix path to mac style. +# +sub unix_to_mac { + my ($path) = @_; + my @path_elements = split ("/", $path); + my $rv = ""; + my $i; + + foreach $i (0 .. $#path_elements) { + if ($path_elements[$i] eq ".") { + if (!($rv =~ /\:$/)) { + $rv .= ":"; + } + } elsif ($path_elements[$i] eq "..") { + if (!($rv =~ /\:$/)) { + $rv .= "::"; + } else { + $rv .= ":"; + } + } elsif ($path_elements[$i] ne "") { + $rv .= $path_elements[$i] . ":"; + } + + } + + $rv =~ s/\:$//; + + return $rv; +} + +# +# Convert unix path to win style. +# +sub unix_to_win { + my ($path) = @_; + + if ($path_sep ne $win_sep) { + $path =~ s/$path_sep/$win_sep/g; + } + + return $path; +} + +# +# Windows shells require "/" or "\" as path separator. +# Find out the one used in the current Windows shell. +# +sub get_win_sep { + my $path = $ENV{"PATH"} || $ENV{"Path"} || $ENV{"path"}; + $path =~ /\\|\//; + return $&; +} + +# +# Convert unix path to correct style based on platform. +# +sub xp_path { + my ($path) = @_; + + if ($os_type eq "MAC") { + return &unix_to_mac($path); + } elsif($os_type eq "WIN") { + return &unix_to_win($path); + } else { + return $path; + } +} + +# +# given a directory, return an array of all subdirectories +# +sub get_subdirs { + my ($dir) = @_; + my @subdirs; + + if ($os_type ne "MAC") { + if (!($dir =~ /\/$/)) { + $dir = $dir . "/"; + } + } else { + if (!($dir =~ /\:$/)) { + $dir = $dir . ":"; + } + } + opendir (DIR, $dir) || die ("couldn't open directory $dir: $!"); + my @testdir_contents = readdir(DIR); + closedir(DIR); + + foreach (@testdir_contents) { + if ((-d ($dir . $_)) && ($_ ne 'CVS') && ($_ ne '.') && ($_ ne '..')) { + @subdirs[$#subdirs + 1] = $_; + } + } + + return @subdirs; +} + +# +# given a directory, return an array of all the js files that are in it. +# +sub get_js_files { + my ($test_subdir) = @_; + my (@js_file_array, @subdir_files); + + opendir (TEST_SUBDIR, $test_subdir) || die ("couldn't open directory " . + "$test_subdir: $!"); + @subdir_files = readdir(TEST_SUBDIR); + closedir( TEST_SUBDIR ); + + foreach (@subdir_files) { + if ($_ =~ /\.js$/) { + $js_file_array[$#js_file_array+1] = $_; + } + } + + return @js_file_array; +} + +sub report_failure { + my ($test, $message, $bug_number) = @_; + my $bug_line = ""; + + $failures_reported++; + + $message =~ s/\n+/\n/g; + $test =~ s/\:/\//g; + + if ($opt_console_failures) { + if($bug_number) { + print STDERR ("*-* Testcase $test failed:\nBug Number $bug_number". + "\n$message\n"); + } else { + print STDERR ("*-* Testcase $test failed:\n$message\n"); + } + } + + $message =~ s/\n/
\n/g; + $html .= ""; + + if ($bug_number) { + my $bug_url = ($bug_number =~ /^\d+$/) ? "$opt_bug_url$bug_number" : $bug_number; + $bug_line = "". + "Bug Number $bug_number"; + } + + if ($opt_lxr_url) { + $test =~ /\/?([^\/]+\/[^\/]+\/[^\/]+)$/; + $test = $1; + $html .= "
". + "Testcase $1 " . + "failed $bug_line
\n"; + } else { + $html .= "
". + "Testcase $test failed $bug_line
\n"; + } + + $html .= " [ "; + if ($failures_reported > 1) { + $html .= "" . + "Previous Failure | "; + } + + $html .= "" . + "Next Failure | " . + "Top of Page ]
\n" . + "$message
\n"; + + @failed_tests[$#failed_tests + 1] = $test; + +} + +sub dd { + + if ($opt_trace) { + print ("-*- ", @_ , "\n"); + } + +} + +sub status { + + print ("-#- ", @_ , "\n"); + +} + +sub int_handler { + my $resp; + + do { + print ("\n*** User Break: Just [Q]uit, Quit and [R]eport, [C]ontinue ?"); + $resp = ; + } until ($resp =~ /[QqRrCc]/); + + if ($resp =~ /[Qq]/) { + print ("User Exit. No results were generated.\n"); + exit; + } elsif ($resp =~ /[Rr]/) { + $user_exit = 1; + } + +}