aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorGravatar Hoa V. DINH <dinh.viet.hoa@gmail.com>2014-11-25 14:23:25 -0800
committerGravatar Hoa V. DINH <dinh.viet.hoa@gmail.com>2014-11-25 14:23:37 -0800
commit64bf89ebdd0584a6951b68d815a3bb5abd4cdc1d (patch)
tree694a477754c4b29421513780860593337e9b34ba
parent940227a204c088179b1c42f4ccc985c1bced22c4 (diff)
Implemented unit tests for C++ platforms
-rwxr-xr-xbuild-mac/mailcore2.xcodeproj/project.pbxproj166
-rw-r--r--src/core/basetypes/MCArray.cpp18
-rw-r--r--src/core/basetypes/MCArray.h3
-rw-r--r--src/core/basetypes/MCHashMap.cpp23
-rw-r--r--src/core/basetypes/MCHashMap.h3
-rw-r--r--src/core/basetypes/MCNull.cpp14
-rw-r--r--src/core/basetypes/MCString.cpp49
-rw-r--r--src/core/basetypes/MCString.h6
-rw-r--r--unittest/unittest.cpp323
-rw-r--r--unittest/unittest.mm1
10 files changed, 594 insertions, 12 deletions
diff --git a/build-mac/mailcore2.xcodeproj/project.pbxproj b/build-mac/mailcore2.xcodeproj/project.pbxproj
index 73897013..81c82fb0 100755
--- a/build-mac/mailcore2.xcodeproj/project.pbxproj
+++ b/build-mac/mailcore2.xcodeproj/project.pbxproj
@@ -169,6 +169,11 @@
C07AD5D7FD82F8ACAB576231 /* NSError+MCO.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = C07AD44B013BB42A240B4F04 /* NSError+MCO.h */; };
C07AD99B2E2054C684DB8FF6 /* NSError+MCO.mm in Sources */ = {isa = PBXBuildFile; fileRef = C07ADFE43E22B38EFF23ADB5 /* NSError+MCO.mm */; };
C07ADC28B83E7959BF114D46 /* MCOIMAPSession.mm in Sources */ = {isa = PBXBuildFile; fileRef = C07AD057D3C8FBDC7AC95733 /* MCOIMAPSession.mm */; };
+ C600B61C1A242C6A000728F1 /* unittest.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C600B61B1A242C6A000728F1 /* unittest.cpp */; };
+ C600B61D1A244BD1000728F1 /* libMailCore.a in Frameworks */ = {isa = PBXBuildFile; fileRef = C64EA537169E772200778456 /* libMailCore.a */; };
+ C600B6201A244C9A000728F1 /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C6ED6D1917A1919500A4A14C /* Security.framework */; };
+ C600B6211A244CB2000728F1 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C6BD2893170BD71100A91AC1 /* Foundation.framework */; };
+ C600B6231A244CC3000728F1 /* CFNetwork.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C600B6221A244CC3000728F1 /* CFNetwork.framework */; };
C608167517759967001F1018 /* MCSMTPDisconnectOperation.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C608167317759967001F1018 /* MCSMTPDisconnectOperation.cpp */; };
C608167617759968001F1018 /* MCSMTPDisconnectOperation.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C608167317759967001F1018 /* MCSMTPDisconnectOperation.cpp */; };
C608167B177635D2001F1018 /* MCIMAPDisconnectOperation.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C6081679177635D2001F1018 /* MCIMAPDisconnectOperation.cpp */; };
@@ -884,6 +889,13 @@
remoteGlobalIDString = C6BA2B091705F4E6003F0E9E;
remoteInfo = "static mailcore2 ios";
};
+ C600B61E1A244BD8000728F1 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = C64EA52E169E772200778456 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = C64EA536169E772200778456;
+ remoteInfo = "static mailcore2 osx";
+ };
C6A81BB01706852200882C15 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = C64EA52E169E772200778456 /* Project object */;
@@ -915,6 +927,15 @@
/* End PBXContainerItemProxy section */
/* Begin PBXCopyFilesBuildPhase section */
+ C600B6121A242C3F000728F1 /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man1/;
+ dstSubfolderSpec = 0;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
C64EA74B169E854B00778456 /* CopyFiles */ = {
isa = PBXCopyFilesBuildPhase;
buildActionMask = 2147483647;
@@ -1465,6 +1486,9 @@
C07AD057D3C8FBDC7AC95733 /* MCOIMAPSession.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MCOIMAPSession.mm; sourceTree = "<group>"; };
C07AD44B013BB42A240B4F04 /* NSError+MCO.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSError+MCO.h"; sourceTree = "<group>"; };
C07ADFE43E22B38EFF23ADB5 /* NSError+MCO.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = "NSError+MCO.mm"; sourceTree = "<group>"; };
+ C600B6141A242C3F000728F1 /* unittestcpp */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = unittestcpp; sourceTree = BUILT_PRODUCTS_DIR; };
+ C600B61B1A242C6A000728F1 /* unittest.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = unittest.cpp; sourceTree = "<group>"; };
+ C600B6221A244CC3000728F1 /* CFNetwork.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CFNetwork.framework; path = System/Library/Frameworks/CFNetwork.framework; sourceTree = SDKROOT; };
C60136941776B96600A5AF45 /* MCOSMTPOperation+Private.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "MCOSMTPOperation+Private.h"; sourceTree = "<group>"; };
C60136951776C31000A5AF45 /* MCOPOPOperation+Private.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "MCOPOPOperation+Private.h"; sourceTree = "<group>"; };
C608167317759967001F1018 /* MCSMTPDisconnectOperation.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MCSMTPDisconnectOperation.cpp; sourceTree = "<group>"; };
@@ -1886,6 +1910,17 @@
);
runOnlyForDeploymentPostprocessing = 0;
};
+ C600B6111A242C3F000728F1 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ C600B6231A244CC3000728F1 /* CFNetwork.framework in Frameworks */,
+ C600B6211A244CB2000728F1 /* Foundation.framework in Frameworks */,
+ C600B6201A244C9A000728F1 /* Security.framework in Frameworks */,
+ C600B61D1A244BD1000728F1 /* libMailCore.a in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
C64EA534169E772200778456 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
@@ -2136,6 +2171,7 @@
C6BD288D170BD71100A91AC1 /* MailCore.framework */,
27780C3A19CF9CD100C77E44 /* MailCore.framework */,
C6B5AE0219F630B3001352A6 /* unittest.xctest */,
+ C600B6141A242C3F000728F1 /* unittestcpp */,
);
name = Products;
sourceTree = "<group>";
@@ -2472,6 +2508,7 @@
C64EA78E169F259200778456 /* Frameworks */ = {
isa = PBXGroup;
children = (
+ C600B6221A244CC3000728F1 /* CFNetwork.framework */,
C6B5AE1119F63496001352A6 /* Foundation.framework */,
C6B5AE0F19F6347C001352A6 /* Security.framework */,
27780D3419CFA19500C77E44 /* libstdc++.dylib */,
@@ -2519,6 +2556,7 @@
children = (
C6B5B08F19F63542001352A6 /* data */,
C6B5AE0619F630B3001352A6 /* unittest.mm */,
+ C600B61B1A242C6A000728F1 /* unittest.cpp */,
C6B5AE0419F630B3001352A6 /* Supporting Files */,
);
name = unittest;
@@ -2791,6 +2829,24 @@
productReference = 27780C3A19CF9CD100C77E44 /* MailCore.framework */;
productType = "com.apple.product-type.framework";
};
+ C600B6131A242C3F000728F1 /* unittestcpp */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = C600B61A1A242C3F000728F1 /* Build configuration list for PBXNativeTarget "unittestcpp" */;
+ buildPhases = (
+ C600B6101A242C3F000728F1 /* Sources */,
+ C600B6111A242C3F000728F1 /* Frameworks */,
+ C600B6121A242C3F000728F1 /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ C600B61F1A244BD8000728F1 /* PBXTargetDependency */,
+ );
+ name = unittestcpp;
+ productName = unittestcpp;
+ productReference = C600B6141A242C3F000728F1 /* unittestcpp */;
+ productType = "com.apple.product-type.tool";
+ };
C64EA536169E772200778456 /* static mailcore2 osx */ = {
isa = PBXNativeTarget;
buildConfigurationList = C64EA53B169E772200778456 /* Build configuration list for PBXNativeTarget "static mailcore2 osx" */;
@@ -2912,6 +2968,9 @@
LastUpgradeCheck = 0610;
ORGANIZATIONNAME = MailCore;
TargetAttributes = {
+ C600B6131A242C3F000728F1 = {
+ CreatedOnToolsVersion = 6.0;
+ };
C6B5AE0119F630B3001352A6 = {
CreatedOnToolsVersion = 6.0;
};
@@ -2936,6 +2995,7 @@
C6BD288C170BD71100A91AC1 /* mailcore osx */,
27780C2A19CF9CD100C77E44 /* mailcore ios */,
C6B5AE0119F630B3001352A6 /* unittest */,
+ C600B6131A242C3F000728F1 /* unittestcpp */,
);
};
/* End PBXProject section */
@@ -3053,6 +3113,14 @@
);
runOnlyForDeploymentPostprocessing = 0;
};
+ C600B6101A242C3F000728F1 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ C600B61C1A242C6A000728F1 /* unittest.cpp in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
C64EA533169E772200778456 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
@@ -3528,6 +3596,11 @@
target = C6BA2B091705F4E6003F0E9E /* static mailcore2 ios */;
targetProxy = 27780C3F19CF9DE600C77E44 /* PBXContainerItemProxy */;
};
+ C600B61F1A244BD8000728F1 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = C64EA536169E772200778456 /* static mailcore2 osx */;
+ targetProxy = C600B61E1A244BD8000728F1 /* PBXContainerItemProxy */;
+ };
C6A81BB11706852200882C15 /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = C6BA2B091705F4E6003F0E9E /* static mailcore2 ios */;
@@ -3605,6 +3678,91 @@
};
name = Release;
};
+ C600B6181A242C3F000728F1 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
+ CLANG_ENABLE_MODULES = YES;
+ CLANG_ENABLE_OBJC_ARC = YES;
+ CLANG_WARN_BOOL_CONVERSION = YES;
+ CLANG_WARN_CONSTANT_CONVERSION = YES;
+ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+ CLANG_WARN_ENUM_CONVERSION = YES;
+ CLANG_WARN_INT_CONVERSION = YES;
+ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+ CLANG_WARN_UNREACHABLE_CODE = YES;
+ ENABLE_STRICT_OBJC_MSGSEND = YES;
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ "DEBUG=1",
+ "$(inherited)",
+ );
+ GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+ GCC_WARN_UNDECLARED_SELECTOR = YES;
+ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+ GCC_WARN_UNUSED_FUNCTION = YES;
+ MACOSX_DEPLOYMENT_TARGET = 10.10;
+ MTL_ENABLE_DEBUG_INFO = YES;
+ OTHER_LDFLAGS = (
+ "-luchardet",
+ "-lctemplate",
+ "-letpan",
+ "-lxml2",
+ "-lsasl2",
+ "-liconv",
+ "-ltidy",
+ "-lz",
+ "-lc++",
+ "-stdlib=libc++",
+ "-ObjC",
+ "-lcrypto",
+ "-lssl",
+ );
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ SDKROOT = macosx;
+ };
+ name = Debug;
+ };
+ C600B6191A242C3F000728F1 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
+ CLANG_ENABLE_MODULES = YES;
+ CLANG_ENABLE_OBJC_ARC = YES;
+ CLANG_WARN_BOOL_CONVERSION = YES;
+ CLANG_WARN_CONSTANT_CONVERSION = YES;
+ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+ CLANG_WARN_ENUM_CONVERSION = YES;
+ CLANG_WARN_INT_CONVERSION = YES;
+ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+ CLANG_WARN_UNREACHABLE_CODE = YES;
+ ENABLE_NS_ASSERTIONS = NO;
+ ENABLE_STRICT_OBJC_MSGSEND = YES;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+ GCC_WARN_UNDECLARED_SELECTOR = YES;
+ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+ GCC_WARN_UNUSED_FUNCTION = YES;
+ MACOSX_DEPLOYMENT_TARGET = 10.10;
+ MTL_ENABLE_DEBUG_INFO = NO;
+ OTHER_LDFLAGS = (
+ "-luchardet",
+ "-lctemplate",
+ "-letpan",
+ "-lxml2",
+ "-lsasl2",
+ "-liconv",
+ "-ltidy",
+ "-lz",
+ "-lc++",
+ "-stdlib=libc++",
+ "-ObjC",
+ "-lcrypto",
+ "-lssl",
+ );
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ SDKROOT = macosx;
+ };
+ name = Release;
+ };
C64EA539169E772200778456 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
@@ -3963,6 +4121,14 @@
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
+ C600B61A1A242C3F000728F1 /* Build configuration list for PBXNativeTarget "unittestcpp" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ C600B6181A242C3F000728F1 /* Debug */,
+ C600B6191A242C3F000728F1 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ };
C64EA531169E772200778456 /* Build configuration list for PBXProject "mailcore2" */ = {
isa = XCConfigurationList;
buildConfigurations = (
diff --git a/src/core/basetypes/MCArray.cpp b/src/core/basetypes/MCArray.cpp
index 787dd0ba..9fa69ccb 100644
--- a/src/core/basetypes/MCArray.cpp
+++ b/src/core/basetypes/MCArray.cpp
@@ -253,6 +253,24 @@ String * Array::componentsJoinedByString(String * delimiter)
return result;
}
+bool Array::isEqual(Object * otherObject)
+{
+ Array * otherArray = (Array *) otherObject;
+ if (otherArray->count() != count()) {
+ return false;
+ }
+ bool result = true;
+ mc_foreacharrayIndex(i, Object, value, this) {
+ Object * otherValue = otherArray->objectAtIndex(i);
+ if (!value->isEqual(otherValue)) {
+ result = false;
+ break;
+ }
+ }
+
+ return result;
+}
+
HashMap * Array::serializable()
{
HashMap * result = Object::serializable();
diff --git a/src/core/basetypes/MCArray.h b/src/core/basetypes/MCArray.h
index 7e82ad9e..655eee5f 100644
--- a/src/core/basetypes/MCArray.h
+++ b/src/core/basetypes/MCArray.h
@@ -45,7 +45,8 @@ namespace mailcore {
virtual Object * copy();
virtual HashMap * serializable();
virtual void importSerializable(HashMap * serializable);
-
+ virtual bool isEqual(Object * otherObject);
+
private:
carray * mArray;
void init();
diff --git a/src/core/basetypes/MCHashMap.cpp b/src/core/basetypes/MCHashMap.cpp
index 046aad90..486707e9 100644
--- a/src/core/basetypes/MCHashMap.cpp
+++ b/src/core/basetypes/MCHashMap.cpp
@@ -281,6 +281,29 @@ void HashMap::removeAllObjects()
mCount = 0;
}
+bool HashMap::isEqual(Object * otherObject)
+{
+ HashMap * otherMap = (HashMap *) otherObject;
+ if (otherMap->count() != count()) {
+ return false;
+ }
+ bool result = true;
+ mc_foreachhashmapKeyAndValue(Object, key, Object, value, this) {
+ Object * otherValue = otherMap->objectForKey(key);
+ if (otherValue == NULL) {
+ result = false;
+ break;
+ }
+ if (!value->isEqual(otherValue)) {
+ fprintf(stderr, "%s: %s %s\n", MCUTF8(key), MCUTF8(value), MCUTF8(otherValue));
+ result = false;
+ break;
+ }
+ }
+
+ return result;
+}
+
HashMap * HashMap::serializable()
{
HashMap * result = Object::serializable();
diff --git a/src/core/basetypes/MCHashMap.h b/src/core/basetypes/MCHashMap.h
index 93938383..b6ac6d2f 100644
--- a/src/core/basetypes/MCHashMap.h
+++ b/src/core/basetypes/MCHashMap.h
@@ -34,7 +34,8 @@ namespace mailcore {
virtual Object * copy();
virtual HashMap * serializable();
virtual void importSerializable(HashMap * serializable);
-
+ virtual bool isEqual(Object * otherObject);
+
private:
unsigned int mAllocated;
unsigned int mCount;
diff --git a/src/core/basetypes/MCNull.cpp b/src/core/basetypes/MCNull.cpp
index cdb8335f..53d50622 100644
--- a/src/core/basetypes/MCNull.cpp
+++ b/src/core/basetypes/MCNull.cpp
@@ -10,10 +10,16 @@
using namespace mailcore;
-Null * Null::null()
+static Null * s_null = NULL;
+static pthread_once_t s_once;
+
+static void init_null(void)
{
- Null * result = new Null();
- result->autorelease();
- return result;
+ s_null = new Null();
}
+Null * Null::null()
+{
+ pthread_once(&s_once, init_null);
+ return s_null;
+}
diff --git a/src/core/basetypes/MCString.cpp b/src/core/basetypes/MCString.cpp
index c17c7074..b3beeb40 100644
--- a/src/core/basetypes/MCString.cpp
+++ b/src/core/basetypes/MCString.cpp
@@ -1184,6 +1184,9 @@ Data * String::encodedMIMEHeaderValueForSubject()
int String::compareWithCaseSensitive(String * otherString, bool caseSensitive)
{
+ if ((length() == 0) && (otherString->length() == 0)) {
+ return 0;
+ }
if ((unicodeCharacters() == NULL) && (otherString->unicodeCharacters() != NULL)) {
return 0;
}
@@ -1486,6 +1489,17 @@ int String::locationOfString(String * occurrence)
return (int) (location - mUnicodeChars);
}
+int String::lastLocationOfString(String * occurrence)
+{
+ UChar * location;
+ location = u_strrstr(mUnicodeChars, occurrence->unicodeCharacters());
+ if (location == NULL) {
+ return -1;
+ }
+
+ return (int) (location - mUnicodeChars);
+}
+
#pragma mark strip HTML
struct parserState {
@@ -2143,10 +2157,37 @@ String * String::stringByAppendingPathComponent(String * component)
String * String::stringByDeletingLastPathComponent()
{
- String * component = lastPathComponent();
- String * result = (String *) this->copy()->autorelease();
- result->deleteCharactersInRange(RangeMake(result->length() - component->length(), component->length()));
- return result;
+ String * currentString = this;
+ if (currentString->isEqual(MCSTR("/"))) {
+ return currentString;
+ }
+ if (currentString->length() == 0) {
+ return currentString;
+ }
+ if (currentString->unicodeCharacters()[currentString->length() - 1] == '/') {
+ currentString = currentString->substringToIndex(currentString->length() - 1);
+ }
+ String * component = currentString->lastPathComponent();
+ currentString = currentString->substringToIndex(currentString->length() - component->length());
+ if (currentString->isEqual(MCSTR("/"))) {
+ return currentString;
+ }
+ if (currentString->length() == 0) {
+ return currentString;
+ }
+ if (currentString->unicodeCharacters()[currentString->length() - 1] == '/') {
+ currentString = currentString->substringToIndex(currentString->length() - 1);
+ }
+ return currentString;
+}
+
+String * String::stringByDeletingPathExtension()
+{
+ int location = lastLocationOfString(MCSTR("."));
+ if ((location == -1) || (location == 0)) {
+ return this;
+ }
+ return substringToIndex(location);
}
Array * String::componentsSeparatedByString(String * separator)
diff --git a/src/core/basetypes/MCString.h b/src/core/basetypes/MCString.h
index 842ff5b8..cbe5538b 100644
--- a/src/core/basetypes/MCString.h
+++ b/src/core/basetypes/MCString.h
@@ -52,7 +52,8 @@ namespace mailcore {
virtual String * stringByAppendingCharacters(const UChar * unicodeCharacters);
virtual String * stringByAppendingPathComponent(String * component);
virtual String * stringByDeletingLastPathComponent();
-
+ virtual String * stringByDeletingPathExtension();
+
virtual int compare(String * otherString);
virtual int caseInsensitiveCompare(String * otherString);
virtual String * lowercaseString();
@@ -62,7 +63,8 @@ namespace mailcore {
virtual void deleteCharactersInRange(Range range);
virtual unsigned int replaceOccurrencesOfString(String * occurrence, String * replacement);
virtual int locationOfString(String * occurrence);
-
+ virtual int lastLocationOfString(String * occurrence);
+
virtual Array * componentsSeparatedByString(String * separator);
virtual bool isEqualCaseInsensitive(String * otherString);
diff --git a/unittest/unittest.cpp b/unittest/unittest.cpp
new file mode 100644
index 00000000..a96a82e2
--- /dev/null
+++ b/unittest/unittest.cpp
@@ -0,0 +1,323 @@
+#include <MailCore/MailCore.h>
+#include <dirent.h>
+
+using namespace mailcore;
+
+static int global_failure = 0;
+static int global_success = 0;
+
+static time_t referenceDate(void)
+{
+ struct tm aTm;
+ memset(&aTm, 0, sizeof(aTm));
+ aTm.tm_sec = 0;
+ aTm.tm_min = 0;
+ aTm.tm_hour = 16;
+ aTm.tm_mday = 31;
+ aTm.tm_mon = 11;
+ aTm.tm_year = 2000 - 1900;
+ time_t date = mktime(&aTm);
+ return date;
+}
+
+static void testMessageBuilder1(String * path)
+{
+ printf("testMessageBuilder1\n");
+ MessageBuilder * builder = new MessageBuilder();
+ builder->header()->setFrom(Address::addressWithRFC822String(MCSTR("Hoà <dinh.viet.hoa@gmail.com>")));
+ builder->header()->setTo(Array::arrayWithObject(Address::addressWithRFC822String(MCSTR("Foo Bar <dinh.viet.hoa@gmail.com>"))));
+ builder->header()->setSubject(MCSTR("testMessageBuilder1"));
+ builder->header()->setDate(referenceDate());
+ builder->header()->setMessageID(MCSTR("MyMessageID123@mail.gmail.com"));
+ builder->setHTMLBody(MCSTR("<html><body>This is a HTML content</body></html>"));
+ Array * boundaries = Array::array();
+ boundaries->addObject(MCSTR("1"));
+ boundaries->addObject(MCSTR("2"));
+ boundaries->addObject(MCSTR("3"));
+ boundaries->addObject(MCSTR("4"));
+ boundaries->addObject(MCSTR("5"));
+ builder->setBoundaries(boundaries);
+ String * outputPath = path->stringByAppendingPathComponent(MCSTR("output/builder1.eml"));
+ Data * expectedData = Data::dataWithContentsOfFile(outputPath);
+ if (!builder->data()->isEqual(expectedData)) {
+ printf("testMessageBuilder1 failed\n");
+ fprintf(stderr, "current:\n%s\n", MCUTF8(builder->data()->stringWithCharset("utf-8")));
+ fprintf(stderr, "expected:\n%s\n", MCUTF8(expectedData->stringWithCharset("utf-8")));
+ global_failure ++;
+ return;
+ }
+ printf("testMessageBuilder1 ok\n");
+ global_success ++;
+}
+
+static void testMessageBuilder2(String * path)
+{
+ printf("testMessageBuilder2\n");
+ MessageBuilder * builder = new MessageBuilder();
+ builder->header()->setFrom(Address::addressWithRFC822String(MCSTR("Hoà <dinh.viet.hoa@gmail.com>")));
+ Array * to = Array::array();
+ to->addObject(Address::addressWithRFC822String(MCSTR("Foo Bar <dinh.viet.hoa@gmail.com>")));
+ to->addObject(Address::addressWithRFC822String(MCSTR("Other Recipient <another-foobar@to-recipient.org>")));
+ builder->header()->setTo(to);
+ Array * cc = Array::array();
+ cc->addObject(Address::addressWithRFC822String(MCSTR("Carbon Copy <dinh.viet.hoa@gmail.com>")));
+ cc->addObject(Address::addressWithRFC822String(MCSTR("Other Recipient <another-foobar@to-recipient.org>")));
+ builder->header()->setCc(cc);
+ builder->header()->setSubject(MCSTR("testMessageBuilder2"));
+ builder->header()->setDate(referenceDate());
+ builder->header()->setMessageID(MCSTR("MyMessageID123@mail.gmail.com"));
+ builder->setHTMLBody(MCSTR("<html><body>This is a HTML content</body></html>"));
+ String * attachmentPath = path->stringByAppendingPathComponent(MCSTR("input/photo.jpg"));
+ builder->addAttachment(Attachment::attachmentWithContentsOfFile(attachmentPath));
+ attachmentPath = path->stringByAppendingPathComponent(MCSTR("input/photo2.jpg"));
+ builder->addAttachment(Attachment::attachmentWithContentsOfFile(attachmentPath));
+ Array * boundaries = Array::array();
+ boundaries->addObject(MCSTR("1"));
+ boundaries->addObject(MCSTR("2"));
+ boundaries->addObject(MCSTR("3"));
+ boundaries->addObject(MCSTR("4"));
+ boundaries->addObject(MCSTR("5"));
+ builder->setBoundaries(boundaries);
+ String * outputPath = path->stringByAppendingPathComponent(MCSTR("output/builder2.eml"));
+ Data * expectedData = Data::dataWithContentsOfFile(outputPath);
+ if (!builder->data()->isEqual(expectedData)) {
+ printf("testMessageBuilder2 failed\n");
+ fprintf(stderr, "current:\n%s\n", MCUTF8(builder->data()->stringWithCharset("utf-8")));
+ fprintf(stderr, "expected:\n%s\n", MCUTF8(expectedData->stringWithCharset("utf-8")));
+ global_failure ++;
+ return;
+ }
+ printf("testMessageBuilder2 ok\n");
+ global_success ++;
+}
+
+static void testMessageBuilder3(String * path)
+{
+ printf("testMessageBuilder3\n");
+ MessageBuilder * builder = new MessageBuilder();
+ builder->header()->setFrom(Address::addressWithRFC822String(MCSTR("Hoà <dinh.viet.hoa@gmail.com>")));
+ Array * to = Array::array();
+ to->addObject(Address::addressWithRFC822String(MCSTR("Foo Bar <dinh.viet.hoa@gmail.com>")));
+ to->addObject(Address::addressWithRFC822String(MCSTR("Other Recipient <another-foobar@to-recipient.org>")));
+ builder->header()->setTo(to);
+ Array * cc = Array::array();
+ cc->addObject(Address::addressWithRFC822String(MCSTR("Carbon Copy <dinh.viet.hoa@gmail.com>")));
+ cc->addObject(Address::addressWithRFC822String(MCSTR("Other Recipient <another-foobar@to-recipient.org>")));
+ builder->header()->setCc(cc);
+ builder->header()->setSubject(MCSTR("testMessageBuilder3"));
+ builder->header()->setDate(referenceDate());
+ builder->header()->setMessageID(MCSTR("MyMessageID123@mail.gmail.com"));
+ builder->setHTMLBody(MCSTR("<html><body><div>This is a HTML content</div><div><img src=\"cid:123\"></div></body></html>"));
+ String * attachmentPath = path->stringByAppendingPathComponent(MCSTR("input/photo.jpg"));
+ builder->addAttachment(Attachment::attachmentWithContentsOfFile(attachmentPath));
+ attachmentPath = path->stringByAppendingPathComponent(MCSTR("input/photo2.jpg"));
+ Attachment * attachment = Attachment::attachmentWithContentsOfFile(attachmentPath);
+ attachment->setContentID(MCSTR("123"));
+ builder->addRelatedAttachment(attachment);
+ Array * boundaries = Array::array();
+ boundaries->addObject(MCSTR("1"));
+ boundaries->addObject(MCSTR("2"));
+ boundaries->addObject(MCSTR("3"));
+ boundaries->addObject(MCSTR("4"));
+ boundaries->addObject(MCSTR("5"));
+ builder->setBoundaries(boundaries);
+ String * outputPath = path->stringByAppendingPathComponent(MCSTR("output/builder3.eml"));
+ Data * expectedData = Data::dataWithContentsOfFile(outputPath);
+ if (!builder->data()->isEqual(expectedData)) {
+ printf("testMessageBuilder3 failed\n");
+ fprintf(stderr, "current:\n%s\n", MCUTF8(builder->data()->stringWithCharset("utf-8")));
+ fprintf(stderr, "expected:\n%s\n", MCUTF8(expectedData->stringWithCharset("utf-8")));
+ global_failure ++;
+ return;
+ }
+ printf("testMessageBuilder3 ok\n");
+ global_success ++;
+}
+
+static Array * pathsInDirectory(String * directory)
+{
+ Array * result = Array::array();
+
+ DIR * dir = opendir(directory->fileSystemRepresentation());
+ if (dir == NULL) {
+ return result;
+ }
+
+ struct dirent * ent;
+ while ((ent = readdir(dir)) != NULL) {
+ if (ent->d_name[0] == '.') {
+ continue;
+ }
+
+ String * subpath = directory->stringByAppendingPathComponent(String::stringWithFileSystemRepresentation(ent->d_name));
+ if (ent->d_type == DT_DIR) {
+ result->addObjectsFromArray(pathsInDirectory(subpath));
+ }
+ else {
+ result->addObject(subpath);
+ }
+ }
+ closedir(dir);
+
+ return result;
+}
+
+static void prepareHeaderForUnitTest(MessageHeader * header)
+{
+ time_t now = time(NULL);
+ if (fabs(now - header->date()) <= 2) {
+ // Date might be generated, set to known date.
+ header->setDate(referenceDate());
+ }
+ if (fabs(header->receivedDate() - now) <= 2) {
+ // Date might be generated, set to known date.
+ header->setReceivedDate(referenceDate());
+ }
+ if (header->isMessageIDAutoGenerated()) {
+ header->setMessageID(MCSTR("MyMessageID123@mail.gmail.com"));
+ }
+}
+
+static void preparePartForUnitTest(AbstractPart * part)
+{
+ if (part->className()->isEqual(MCSTR("mailcore::Multipart"))) {
+ Multipart * multipart = (Multipart *) part;
+ for(unsigned int i = 0 ; i < multipart->parts()->count() ; i ++) {
+ preparePartForUnitTest((AbstractPart *) multipart->parts()->objectAtIndex(i));
+ }
+ }
+ else if (part->className()->isEqual(MCSTR("mailcore::MessagePart"))) {
+ prepareHeaderForUnitTest(((MessagePart *) part)->header());
+ preparePartForUnitTest(((MessagePart *) part)->mainPart());
+ }
+}
+
+static void testMessageParser(String * path)
+{
+ printf("testMessageParser\n");
+ String * inputPath = path->stringByAppendingPathComponent(MCSTR("input"));
+ String * outputPath = path->stringByAppendingPathComponent(MCSTR("output"));
+ Array * list = pathsInDirectory(inputPath);
+ int failure = 0;
+ int success = 0;
+ mc_foreacharray(String, filename, list) {
+ MessageParser * parser = MessageParser::messageParserWithContentsOfFile(filename);
+ prepareHeaderForUnitTest(parser->header());
+ preparePartForUnitTest(parser->mainPart());
+ HashMap * result = parser->serializable();
+ String * expectedPath = outputPath->stringByAppendingPathComponent(filename->substringFromIndex(inputPath->length()));
+ //fprintf(stderr, "expected: %s\n", MCUTF8(expectedPath));
+ HashMap * expectedResult = (HashMap *) JSON::objectFromJSONData(Data::dataWithContentsOfFile(expectedPath));
+ if (result->isEqual(expectedResult)) {
+ success ++;
+ }
+ else {
+ fprintf(stderr, "testMessageParser: failed for %s\n", MCUTF8(filename));
+ fprintf(stderr, "expected: %s\n", MCUTF8(expectedResult));
+ fprintf(stderr, "got: %s\n", MCUTF8(result));
+ failure ++;
+ }
+ }
+ if (failure > 0) {
+ printf("testMessageParser ok: %i succeeded, %i failed\n", success, failure);
+ global_failure ++;
+ return;
+ }
+ printf("testMessageParser ok: %i succeeded\n", success);
+ global_success ++;
+}
+
+static void testCharsetDetection(String * path)
+{
+ printf("testCharsetDetection\n");
+ String * inputPath = path->stringByAppendingPathComponent(MCSTR("input"));
+ Array * list = pathsInDirectory(inputPath);
+ int failure = 0;
+ int success = 0;
+ mc_foreacharray(String, filename, list) {
+ Data * data = Data::dataWithContentsOfFile(filename);
+ String * charset = data->charsetWithFilteredHTML(false);
+ charset = charset->lowercaseString();
+ if (!filename->lastPathComponent()->stringByDeletingPathExtension()->isEqual(charset)) {
+ failure ++;
+ fprintf(stderr, "testCharsetDetection: failed for %s\n", MCUTF8(filename));
+ fprintf(stderr, "got: %s\n", MCUTF8(charset));
+ }
+ else {
+ success ++;
+ }
+ }
+ if (failure > 0) {
+ printf("testCharsetDetection ok: %i succeeded, %i failed\n", success, failure);
+ global_failure ++;
+ return;
+ }
+ printf("testCharsetDetection ok: %i succeeded\n", success);
+ global_success ++;
+}
+
+static void testSummary(String * path)
+{
+ printf("testSummary\n");
+ String * inputPath = path->stringByAppendingPathComponent(MCSTR("input"));
+ String * outputPath = path->stringByAppendingPathComponent(MCSTR("output"));
+ Array * list = pathsInDirectory(inputPath);
+ int failure = 0;
+ int success = 0;
+ mc_foreacharray(String, filename, list) {
+ MessageParser * parser = MessageParser::messageParserWithContentsOfFile(filename);
+ prepareHeaderForUnitTest(parser->header());
+ preparePartForUnitTest(parser->mainPart());
+ String * str = parser->plainTextRendering();
+ String * resultPath = outputPath->stringByAppendingPathComponent(filename->substringFromIndex(inputPath->length()));
+ resultPath = resultPath->stringByDeletingPathExtension()->stringByAppendingString(MCSTR(".txt"));
+ Data * resultData = Data::dataWithContentsOfFile(resultPath);
+ if (resultData == nil) {
+ fprintf(stderr, "test %s is a well-known failing test", MCUTF8(filename));
+ continue;
+ }
+
+ if (!resultData->stringWithCharset("utf-8")->isEqual(str)) {
+ failure ++;
+ fprintf(stderr, "testSummary: failed for %s\n", MCUTF8(filename));
+ fprintf(stderr, "got: %s\n", MCUTF8(str));
+ fprintf(stderr, "expected: %s\n", MCUTF8(resultData->stringWithCharset("utf-8")));
+ }
+ else {
+ success ++;
+ }
+ }
+ if (failure > 0) {
+ printf("testSummary ok: %i succeeded, %i failed\n", success, failure);
+ global_failure ++;
+ return;
+ }
+ printf("testSummary ok: %i succeeded\n", success);
+ global_success ++;
+}
+
+int main(int argc, char ** argv)
+{
+ if (argc < 2) {
+ fprintf(stderr, "syntax: unittestcpp [unittestdatadir]\n");
+ exit(EXIT_FAILURE);
+ }
+
+ AutoreleasePool * pool = new AutoreleasePool();
+
+ String * path = String::stringWithUTF8Characters(argv[1]);
+ printf("data path: %s\n", MCUTF8(path));
+
+ testMessageBuilder1(path->stringByAppendingPathComponent(MCSTR("builder")));
+ testMessageBuilder2(path->stringByAppendingPathComponent(MCSTR("builder")));
+ testMessageBuilder3(path->stringByAppendingPathComponent(MCSTR("builder")));
+ testMessageParser(path->stringByAppendingPathComponent(MCSTR("parser")));
+ testCharsetDetection(path->stringByAppendingPathComponent(MCSTR("charset-detection")));
+ testSummary(path->stringByAppendingPathComponent(MCSTR("summary")));
+
+ printf("%i tests succeeded, %i tests failed\n", global_success, global_failure);
+
+ pool->release();
+
+ exit(EXIT_SUCCESS);
+} \ No newline at end of file
diff --git a/unittest/unittest.mm b/unittest/unittest.mm
index ed5f94d5..2563e9aa 100644
--- a/unittest/unittest.mm
+++ b/unittest/unittest.mm
@@ -225,6 +225,7 @@
NSData * data = [NSData dataWithContentsOfFile:path];
MCOMessageParser * parser = [MCOMessageParser messageParserWithData:data];
[[parser header] prepareForUnitTest];
+ [[parser mainPart] prepareForUnitTest];
NSString * str = [parser plainTextRendering];
// NSString * outputPath = [@"/Users/hoa/mc2-results/summary" stringByAppendingPathComponent:name];