merge of '38bdad32536cc97eb69bad5515fa682a452c9be6'

and '69348ff83b958e39e8d6bdc38da8a1f1ea4ace1a'

Monotone-Parent: 38bdad32536cc97eb69bad5515fa682a452c9be6
Monotone-Parent: 69348ff83b958e39e8d6bdc38da8a1f1ea4ace1a
Monotone-Revision: 0b152b3b9b68eb80edffbcf7dec3d59fa6a7e76d

Monotone-Author: flachapelle@inverse.ca
Monotone-Date: 2010-01-25T16:03:26
Monotone-Branch: ca.inverse.sogo
This commit is contained in:
Francis Lachapelle 2010-01-25 16:03:26 +00:00
commit 8937d26b92
32 changed files with 188 additions and 98 deletions

View file

@ -21,4 +21,4 @@ SOPE/NGCards/samples/CardElement.m
SOPE/NGCards/samples/CardGroup.m
SOPE/NGCards/samples/CardVersitRenderer.m
SOPE/NGCards/samples/NGCardsSaxHandler.m
Tests/config.py
Tests/Integration/config.py

View file

@ -1,3 +1,7 @@
2010-01-24 Ludovic Marcotte <lmarcotte@inverse.ca>
* Reorganized the layout of automated tests.
2010-01-22 Francis Lachapelle <flachapelle@inverse.ca>
* UI/Contacts/UIxListEditor.m (-references): avoid printing the
@ -8,6 +12,9 @@
2010-01-22 Wolfgang Sourdeau <wsourdeau@inverse.ca>
* UI/WebServerResources/MailerUI.js (composeNewMessage): fixed
potential js error in IE when no mailbox is selected.
* Tools/SOGoToolRestore.m (+initialize): we need to invoke
[iCalEntityObject+SOGo initializeSOGoExtensions], otherwise the
extraction of quick records will cause a crash because some global

View file

@ -1772,7 +1772,24 @@ Index: sope-mime/NGImap4/NGImap4ResponseParser.m
static __inline__ NSException *_consumeIfMatch
(NGImap4ResponseParser *self, unsigned char _m);
@@ -488,6 +493,50 @@
@@ -300,6 +305,16 @@
/* those starting with a number '24 ', eg '24 OK Completed' */
endOfCommand = (_parseTaggedResponse(self, result) == _tag);
}
+ else if (l0 == -1) {
+ *ex_ = [self->buffer lastException];
+ if (!*ex_)
+ *ex_
+ = [NSException exceptionWithName:@"UnexpectedEndOfStream"
+ reason:(@"the parsed stream ended"
+ @" unexpectedly")
+ userInfo:nil];
+ endOfCommand = YES;
+ }
}
return result;
}
@@ -488,6 +503,50 @@
return [self _parseDataIntoRAM:size];
}
@ -1823,7 +1840,7 @@ Index: sope-mime/NGImap4/NGImap4ResponseParser.m
static int _parseTaggedResponse(NGImap4ResponseParser *self,
NGMutableHashMap *result_)
{
@@ -584,6 +633,10 @@
@@ -584,6 +643,10 @@
break;
case 'N':
@ -1834,7 +1851,7 @@ Index: sope-mime/NGImap4/NGImap4ResponseParser.m
if (_parseNoUntaggedResponse(self, result_)) // la: 2
return;
break;
@@ -648,14 +701,171 @@
@@ -648,14 +711,171 @@
[result_ addObject:_parseUntil(self, '\n') forKey:@"description"];
}
@ -2007,7 +2024,7 @@ Index: sope-mime/NGImap4/NGImap4ResponseParser.m
- (void)_consumeOptionalSpace {
if (_la(self, 0) == ' ') _consume(self, 1);
}
@@ -685,6 +895,10 @@
@@ -685,6 +905,10 @@
name = [self _parseQuotedString];
_parseUntil(self, '\n');
}
@ -2018,7 +2035,7 @@ Index: sope-mime/NGImap4/NGImap4ResponseParser.m
else
name = _parseUntil(self, '\n');
@@ -723,6 +937,85 @@
@@ -723,6 +947,85 @@
return YES;
}
@ -2104,7 +2121,7 @@ Index: sope-mime/NGImap4/NGImap4ResponseParser.m
- (BOOL)_parseACLResponseIntoHashMap:(NGMutableHashMap *)result_ {
/*
21 GETACL INBOX
@@ -1030,10 +1323,15 @@
@@ -1030,10 +1333,15 @@
_consume(self, 7);
if (_la(self, 0) == '"') {
@ -2122,7 +2139,7 @@ Index: sope-mime/NGImap4/NGImap4ResponseParser.m
else {
name = _parseUntil(self, ' ');
}
@@ -1073,51 +1371,6 @@
@@ -1073,51 +1381,6 @@
return YES;
}
@ -2174,7 +2191,7 @@ Index: sope-mime/NGImap4/NGImap4ResponseParser.m
- (id)_decodeQP:(id)_string headerField:(NSString *)_field {
if (![_string isNotNull])
return _string;
@@ -1185,7 +1438,7 @@
@@ -1185,7 +1448,7 @@
route = [self _parseQuotedStringOrNIL]; [self _consumeOptionalSpace];
mailbox = [self _parseQuotedStringOrNIL]; [self _consumeOptionalSpace];
host = [self _parseQuotedStringOrNIL]; [self _consumeOptionalSpace];
@ -2183,7 +2200,7 @@ Index: sope-mime/NGImap4/NGImap4ResponseParser.m
if (_la(self, 0) != ')') {
[self logWithFormat:@"WARNING: IMAP4 envelope "
@"address not properly closed (c0=%c,c1=%c): %@",
@@ -1197,6 +1450,7 @@
@@ -1197,6 +1460,7 @@
address = [[NGImap4EnvelopeAddress alloc] initWithPersonalName:pname
sourceRoute:route mailbox:mailbox
host:host];
@ -2191,7 +2208,7 @@ Index: sope-mime/NGImap4/NGImap4ResponseParser.m
return address;
}
@@ -1382,7 +1636,15 @@
@@ -1382,7 +1646,15 @@
#if 0
[self logWithFormat:@"PARSE KEY: %@", key];
#endif
@ -2208,7 +2225,7 @@ Index: sope-mime/NGImap4/NGImap4ResponseParser.m
NSDictionary *content;
if ((content = [self _parseBodyContent]) != nil)
@@ -1594,8 +1856,11 @@
@@ -1594,8 +1866,11 @@
if (_decode)
data = [data decodeQuotedPrintableValueOfMIMEHeaderField:nil];
@ -2222,7 +2239,7 @@ Index: sope-mime/NGImap4/NGImap4ResponseParser.m
}
else {
str = _parseUntil2(self, ' ', ')');
@@ -1620,13 +1885,35 @@
@@ -1620,13 +1895,35 @@
return str;
}
@ -2259,7 +2276,7 @@ Index: sope-mime/NGImap4/NGImap4ResponseParser.m
static NSDictionary *_parseBodyParameterList(NGImap4ResponseParser *self)
{
NSMutableDictionary *list;
@@ -1646,7 +1933,7 @@
@@ -1646,7 +1943,7 @@
_consumeIfMatch(self, ' ');
value = _parseBodyDecodeString(self, YES, YES);
@ -2268,7 +2285,7 @@ Index: sope-mime/NGImap4/NGImap4ResponseParser.m
}
_consumeIfMatch(self, ')');
}
@@ -1731,13 +2018,14 @@
@@ -1731,13 +2028,14 @@
static NSDictionary *_parseSingleBody(NGImap4ResponseParser *self,
BOOL isBodyStructure) {
NSString *type, *subtype, *bodyId, *description,
@ -2285,7 +2302,7 @@ Index: sope-mime/NGImap4/NGImap4ResponseParser.m
_consumeIfMatch(self, ' ');
parameterList = _parseBodyParameterList(self);
_consumeIfMatch(self, ' ');
@@ -1762,13 +2050,18 @@
@@ -1762,13 +2060,18 @@
_consumeIfMatch(self, ' ');
[dict setObject:_parseBodyString(self, YES) forKey:@"lines"];
}
@ -2307,7 +2324,7 @@ Index: sope-mime/NGImap4/NGImap4ResponseParser.m
_consumeIfMatch(self, ' ');
[dict setObject:_parseParenthesizedAddressList(self) forKey:@"from"];
_consumeIfMatch(self, ' ');
@@ -1783,14 +2076,20 @@
@@ -1783,14 +2086,20 @@
_consumeIfMatch(self, ' ');
[dict setObject:_parseParenthesizedAddressList(self) forKey:@"bcc"];
_consumeIfMatch(self, ' ');
@ -2331,7 +2348,7 @@ Index: sope-mime/NGImap4/NGImap4ResponseParser.m
}
}
@@ -1805,14 +2104,9 @@
@@ -1805,14 +2114,9 @@
forKey: @"disposition"];
if (_la(self, 0) != ')') {
_consume(self,1);
@ -2349,7 +2366,7 @@ Index: sope-mime/NGImap4/NGImap4ResponseParser.m
if (_la(self, 0) != ')') {
_consume(self,1);
[dict setObject: _parseBodyString(self, YES)
@@ -1829,6 +2123,7 @@
@@ -1829,6 +2133,7 @@
static NSDictionary *_parseMultipartBody(NGImap4ResponseParser *self,
BOOL isBodyStructure) {
NSMutableArray *parts;
@ -2357,7 +2374,7 @@ Index: sope-mime/NGImap4/NGImap4ResponseParser.m
NSString *kind;
NSMutableDictionary *dict;
@@ -1854,14 +2149,9 @@
@@ -1854,14 +2159,9 @@
forKey: @"disposition"];
if (_la(self, 0) != ')') {
_consume(self,1);
@ -2375,7 +2392,7 @@ Index: sope-mime/NGImap4/NGImap4ResponseParser.m
if (_la(self, 0) != ')') {
_consume(self,1);
[dict setObject: _parseBodyString(self, YES)
@@ -2170,6 +2460,21 @@
@@ -2170,6 +2470,21 @@
}
}
@ -2397,7 +2414,7 @@ Index: sope-mime/NGImap4/NGImap4ResponseParser.m
- (NSException *)exceptionForFailedMatch:(unsigned char)_match
got:(unsigned char)_avail
{
@@ -2225,9 +2530,9 @@
@@ -2225,9 +2540,9 @@
[s release];
if (c == '\n') {
@ -2413,7 +2430,13 @@ Index: sope-mime/NGImap4/ChangeLog
===================================================================
--- sope-mime/NGImap4/ChangeLog (revision 1664)
+++ sope-mime/NGImap4/ChangeLog (working copy)
@@ -1,3 +1,107 @@
@@ -1,3 +1,113 @@
+2010-01-25 Wolfgang Sourdeau <wsourdeau@inverse.ca>
+
+ * NGImap4ResponseParser.m (-parseResponseForTagId:exception:):
+ detect "-1" return code from _la and leave the loop with a proper
+ execption when it occurs.
+
+2010-01-15 Wolfgang Sourdeau <wsourdeau@inverse.ca>
+
+ * NGImap4Connection.m (-doesMailboxExistAtURL:): sometimes an
@ -3347,7 +3370,29 @@ Index: sope-mime/NGMail/NGMailAddressParser.m
}
static inline id parseWhiteSpaces(NGMailAddressParser *self, BOOL _guessMode) {
@@ -84,7 +84,7 @@
@@ -79,12 +79,29 @@
return returnValue;
}
+static void dumpBadString(unichar *text, int length) {
+ char *bytes;
+ NSMutableString *logString;
+ int count, max;
+ max = length * sizeof (unichar);
+ logString = [NSMutableString stringWithCapacity: max];
+ [logString appendString: @"dumping buggy atom string: "];
+ bytes = (char *) text;
+ for (count = 0; count < max; count++) {
+ [logString appendFormat: @"0x%X", bytes[count]];
+ if (count < (max - 1))
+ [logString appendString: @", "];
+ }
+
+ NSLog (@"%@", logString);
+}
+
static inline id parseAtom(NGMailAddressParser *self, BOOL _guessMode) {
int keepPos = self->dataPos; // keep reference for backtracking
id returnValue = nil;
BOOL isAtom = YES;
@ -3356,7 +3401,7 @@ Index: sope-mime/NGMail/NGMailAddressParser.m
int length = 0; // token text length
BOOL done = NO;
@@ -94,7 +94,7 @@
@@ -94,7 +111,7 @@
done = YES;
}
else {
@ -3365,7 +3410,17 @@ Index: sope-mime/NGMail/NGMailAddressParser.m
switch (c) {
case '(' : case ')': case '<': case '>':
@@ -162,7 +162,7 @@
@@ -128,6 +145,9 @@
else {
NSCAssert(length > 0, @"no atom with length=0");
returnValue = [mkStrObj(text, length) autorelease];
+ if (!returnValue) {
+ dumpBadString(text, length);
+ }
NSCAssert([returnValue isKindOfClass:StrClass], @"got no string ..");
}
}
@@ -162,7 +182,7 @@
int keepPos = self->dataPos; // keep reference for backtracking
id returnValue = nil;
BOOL isQText = YES;
@ -3374,7 +3429,7 @@ Index: sope-mime/NGMail/NGMailAddressParser.m
int length = 0; // token text length
BOOL done = YES;
@@ -172,9 +172,9 @@
@@ -172,9 +192,9 @@
done = YES;
}
else {
@ -3386,7 +3441,7 @@ Index: sope-mime/NGMail/NGMailAddressParser.m
case '"' :
case '\\':
case 13 :
@@ -215,7 +215,7 @@
@@ -215,7 +235,7 @@
int keepPos = self->dataPos; // keep reference for backtracking
id returnValue = nil;
BOOL isDText = YES;
@ -3395,7 +3450,7 @@ Index: sope-mime/NGMail/NGMailAddressParser.m
int length = 0; // token text length
BOOL done = YES;
@@ -225,9 +225,9 @@
@@ -225,9 +245,9 @@
done = YES;
}
else {
@ -3407,7 +3462,7 @@ Index: sope-mime/NGMail/NGMailAddressParser.m
case '[': case ']':
case '\\': case 13:
isDText = (length > 0);
@@ -320,42 +320,47 @@
@@ -320,42 +340,47 @@
/* constructors */
+ (id)mailAddressParserWithData:(NSData *)_data {

56
Tests/Integration/README Normal file
View file

@ -0,0 +1,56 @@
setup
-----
(you need "python-simplejson", "python-xml", "python-vobject" and "python-m2crypto"
in order to run the scripts on Debian)
1) copy config.py.in to config.py (make sure to never EVER add it to monotone)
2) edit config.py to suit your environment
3) run the test scripts
runnable scripts
----------------
all.py - run all scripts below at once
test-webdavsync.py - explicit
test-davacl.py - dav acl tests for calendar and addressbook modules
other scripts
-------------
propfind.py - a sample implementation of a PROPFIND request using webdavlib
* developers
------------
- Test methods are always prefixed with "test". Sometimes, it's easier to
track down a problem by enabling only one test at a time. One possible method
is to replace "def test" with "def xtest" and replace it back when the
problems are solved.
- Test failures start with "FAIL:". Those are the ones that indicate possible
bugs in the application, if the test is itself known to work.
For example like this:
======================================================================
FAIL: 'modify' PUBLIC, 'view all' PRIVATE, 'view d&t' confidential
----------------------------------------------------------------------
Traceback (most recent call last):
File "./davacl.py", line 75, in testModifyPublicViewAllPrivateViewDConfidential
self._testRights({ "pu": "m", "pr": "v", "co": "d" })
File "./davacl.py", line 119, in _testRights
self._testCreate(rights)
File "./davacl.py", line 165, in _testCreate
exp_code)
File "./davacl.py", line 107, in _putEvent
% (exp_status, put.response["status"]))
AssertionError: event creation/modification: expected status code '403' (received '201')
- Test errors start with "ERRORS" and most likely indicate a bug in the test
code itself.
- Always set a doc string on the test methods, especially for complex test
cases.
- When writing tests, be aware that contrary to unit tests, functional tests
often imply a logical order between the different steps.

View file

@ -1,56 +1,8 @@
setup
-----
This directory holds automated tests for SOGo.
(you need "python-simplejson", "python-xml", "python-vobject" and "python-m2crypto"
in order to run the scripts on Debian)
We currrently have:
1) copy config.py.in to config.py (make sure to never EVER add it to monotone)
2) edit config.py to suit your environment
3) run the test scripts
- Intregation holds all interated tests that are used to
validate overall DAV functionality right now
runnable scripts
----------------
all.py - run all scripts below at once
test-webdavsync.py - explicit
test-davacl.py - dav acl tests for calendar and addressbook modules
other scripts
-------------
propfind.py - a sample implementation of a PROPFIND request using webdavlib
* developers
------------
- Test methods are always prefixed with "test". Sometimes, it's easier to
track down a problem by enabling only one test at a time. One possible method
is to replace "def test" with "def xtest" and replace it back when the
problems are solved.
- Test failures start with "FAIL:". Those are the ones that indicate possible
bugs in the application, if the test is itself known to work.
For example like this:
======================================================================
FAIL: 'modify' PUBLIC, 'view all' PRIVATE, 'view d&t' confidential
----------------------------------------------------------------------
Traceback (most recent call last):
File "./davacl.py", line 75, in testModifyPublicViewAllPrivateViewDConfidential
self._testRights({ "pu": "m", "pr": "v", "co": "d" })
File "./davacl.py", line 119, in _testRights
self._testCreate(rights)
File "./davacl.py", line 165, in _testCreate
exp_code)
File "./davacl.py", line 107, in _putEvent
% (exp_status, put.response["status"]))
AssertionError: event creation/modification: expected status code '403' (received '201')
- Test errors start with "ERRORS" and most likely indicate a bug in the test
code itself.
- Always set a doc string on the test methods, especially for complex test
cases.
- When writing tests, be aware that contrary to unit tests, functional tests
often imply a logical order between the different steps.
- Unit holds all unit tests

View file

@ -109,7 +109,7 @@
</td>
</tr>
</table>
<span class="caption"><var:string label:value="Phones" /></span>
<span class="caption"><var:string label:value="Phones" /></span>
<table class="frame">
<tr>
<td>

View file

@ -52,13 +52,14 @@
/></label></div>
<var:if condition="mustSynchronize" const:negate="YES"
><div><label><var:string
label:value="Tag:"/><input type="text"
><div><span class="label"><var:string
label:value="Tag:"/></span
><span class="content"><input type="text"
name="calendarSyncTag"
id="calendarSyncTag"
class="textField"
var:value="calendarSyncTag"
/></label
/></span
><var:if condition="synchronizeCalendar"><input type="hidden"
name="originalCalendarSyncTag"
id="originalCalendarSyncTag"

View file

@ -575,9 +575,17 @@ function onComposeMessage() {
}
function composeNewMessage() {
var account = Mailer.currentMailbox.split("/")[1];
var url = ApplicationBaseURL + "/" + encodeURI(account) + "/compose";
openMailComposeWindow(url);
var account;
if (Mailer.currentMailbox)
account = Mailer.currentMailbox.split("/")[1];
else if (mailAccounts.length)
account = mailAccounts[0][0];
else
account = null;
if (account) {
var url = ApplicationBaseURL + "/" + encodeURI(account) + "/compose";
openMailComposeWindow(url);
}
}
function openMailbox(mailbox, reload, idx, updateStatus) {

View file

@ -1972,7 +1972,7 @@ function onCalendarModify(event) {
var url = ApplicationBaseURL + calendarID + "/properties";
var windowID = sanitizeWindowName(calendarID + " properties");
var width = 310;
var height = 260;
var height = 266;
var isWebCalendar = false;
if (UserSettings['Calendar']
&& UserSettings['Calendar']['WebCalendars']) {
@ -1983,7 +1983,7 @@ function onCalendarModify(event) {
}
}
if (isWebCalendar)
height += 25;
height += 21;
else if (calendarID == "/personal")
height -= 25;

View file

@ -11,23 +11,28 @@ FIELDSET
border-top: 1px solid #909090;
border-left: 1px solid #909090; }
FIELDSET DIV
{ margin-left: 20px;
margin-right: 10px; }
SPAN.label
{ cursor: default;
width: 10em;
width: 60px;
text-align: right;
padding-right: 1em;
line-height: 2em;
float: left;
display: block; }
INPUT.checkBox
{ margin-left: 35px; }
SPAN.content
{ display: block;
line-height: 1.5em;
vertical-align: middle; }
SPAN.content INPUT.textField
{ width: 50%; }
{ width: 160px; }
BUTTON#colorButton
{ display: none;
@ -45,6 +50,9 @@ DIV#buttons
INPUT#calendarSyncTag
{ width: 7em; }
LABEL
{ white-space: nowrap; }
#webCalendarUrl SPAN.content
{ white-space: nowrap;
overflow: hidden; }

View file

@ -331,15 +331,18 @@ TABLE#categoriesList
DIV#windowButtons
{ bottom: 11px; }
TABLE.frame,
TABLE.framenocaption
TABLE.frame
{ margin-top: -4px; }
TABLE.framenocaption
{ margin-top: 17px; }
TABLE.frame TBODY
{ padding: 20px; }
UL#calendarList
{ height: 100px; }
{ margin-top: 2px;
height: 100px; }
A.toolbarButton SPAN,
A.toolbarButton:hover SPAN {