diff --git a/.mtn-ignore b/.mtn-ignore index 581bd96cf..4473e0e35 100644 --- a/.mtn-ignore +++ b/.mtn-ignore @@ -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 diff --git a/ChangeLog b/ChangeLog index 698ce982c..71a21fc87 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,7 @@ +2010-01-24 Ludovic Marcotte + + * Reorganized the layout of automated tests. + 2010-01-22 Francis Lachapelle * UI/Contacts/UIxListEditor.m (-references): avoid printing the @@ -8,6 +12,9 @@ 2010-01-22 Wolfgang Sourdeau + * 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 diff --git a/SOPE/sope-patchset-r1664.diff b/SOPE/sope-patchset-r1664.diff index ffc1329c0..55725f30a 100644 --- a/SOPE/sope-patchset-r1664.diff +++ b/SOPE/sope-patchset-r1664.diff @@ -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 ++ ++ * 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 + + * 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 { diff --git a/Tests/Integration/README b/Tests/Integration/README new file mode 100644 index 000000000..db62e4ed4 --- /dev/null +++ b/Tests/Integration/README @@ -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. diff --git a/Tests/all.py b/Tests/Integration/all.py similarity index 100% rename from Tests/all.py rename to Tests/Integration/all.py diff --git a/Tests/config.py.in b/Tests/Integration/config.py.in similarity index 100% rename from Tests/config.py.in rename to Tests/Integration/config.py.in diff --git a/Tests/preferences.py b/Tests/Integration/preferences.py similarity index 100% rename from Tests/preferences.py rename to Tests/Integration/preferences.py diff --git a/Tests/propfind.py b/Tests/Integration/propfind.py similarity index 100% rename from Tests/propfind.py rename to Tests/Integration/propfind.py diff --git a/Tests/test-caldav-scheduling.py b/Tests/Integration/test-caldav-scheduling.py similarity index 100% rename from Tests/test-caldav-scheduling.py rename to Tests/Integration/test-caldav-scheduling.py diff --git a/Tests/test-config.py b/Tests/Integration/test-config.py similarity index 100% rename from Tests/test-config.py rename to Tests/Integration/test-config.py diff --git a/Tests/test-davacl.py b/Tests/Integration/test-davacl.py similarity index 100% rename from Tests/test-davacl.py rename to Tests/Integration/test-davacl.py diff --git a/Tests/test-ical.py b/Tests/Integration/test-ical.py similarity index 100% rename from Tests/test-ical.py rename to Tests/Integration/test-ical.py diff --git a/Tests/test-maildav.py b/Tests/Integration/test-maildav.py similarity index 100% rename from Tests/test-maildav.py rename to Tests/Integration/test-maildav.py diff --git a/Tests/test-webdav.py b/Tests/Integration/test-webdav.py similarity index 100% rename from Tests/test-webdav.py rename to Tests/Integration/test-webdav.py diff --git a/Tests/test-webdavlib.py b/Tests/Integration/test-webdavlib.py similarity index 100% rename from Tests/test-webdavlib.py rename to Tests/Integration/test-webdavlib.py diff --git a/Tests/test-webdavsync.py b/Tests/Integration/test-webdavsync.py similarity index 100% rename from Tests/test-webdavsync.py rename to Tests/Integration/test-webdavsync.py diff --git a/Tests/utilities.py b/Tests/Integration/utilities.py similarity index 100% rename from Tests/utilities.py rename to Tests/Integration/utilities.py diff --git a/Tests/webdavlib.py b/Tests/Integration/webdavlib.py similarity index 100% rename from Tests/webdavlib.py rename to Tests/Integration/webdavlib.py diff --git a/Tests/README b/Tests/README index db62e4ed4..43988570b 100644 --- a/Tests/README +++ b/Tests/README @@ -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 diff --git a/UnitTests/GNUmakefile b/Tests/Unit/GNUmakefile similarity index 100% rename from UnitTests/GNUmakefile rename to Tests/Unit/GNUmakefile diff --git a/UnitTests/SOGoTest.h b/Tests/Unit/SOGoTest.h similarity index 100% rename from UnitTests/SOGoTest.h rename to Tests/Unit/SOGoTest.h diff --git a/UnitTests/SOGoTest.m b/Tests/Unit/SOGoTest.m similarity index 100% rename from UnitTests/SOGoTest.m rename to Tests/Unit/SOGoTest.m diff --git a/UnitTests/SOGoTestRunner.h b/Tests/Unit/SOGoTestRunner.h similarity index 100% rename from UnitTests/SOGoTestRunner.h rename to Tests/Unit/SOGoTestRunner.h diff --git a/UnitTests/SOGoTestRunner.m b/Tests/Unit/SOGoTestRunner.m similarity index 100% rename from UnitTests/SOGoTestRunner.m rename to Tests/Unit/SOGoTestRunner.m diff --git a/UnitTests/TestBSJSONAdditions.m b/Tests/Unit/TestBSJSONAdditions.m similarity index 100% rename from UnitTests/TestBSJSONAdditions.m rename to Tests/Unit/TestBSJSONAdditions.m diff --git a/UnitTests/sogo-tests.m b/Tests/Unit/sogo-tests.m similarity index 100% rename from UnitTests/sogo-tests.m rename to Tests/Unit/sogo-tests.m diff --git a/UI/Templates/ContactsUI/UIxContactEditor.wox b/UI/Templates/ContactsUI/UIxContactEditor.wox index 67531112a..d01544e34 100644 --- a/UI/Templates/ContactsUI/UIxContactEditor.wox +++ b/UI/Templates/ContactsUI/UIxContactEditor.wox @@ -109,7 +109,7 @@ - +
diff --git a/UI/Templates/SchedulerUI/UIxCalendarProperties.wox b/UI/Templates/SchedulerUI/UIxCalendarProperties.wox index 05b11c9e8..0e31355f3 100644 --- a/UI/Templates/SchedulerUI/UIxCalendarProperties.wox +++ b/UI/Templates/SchedulerUI/UIxCalendarProperties.wox @@ -52,13 +52,14 @@ />