aboutsummaryrefslogtreecommitdiff
path: root/vmime-master/tests
diff options
context:
space:
mode:
Diffstat (limited to 'vmime-master/tests')
-rw-r--r--vmime-master/tests/misc/importanceHelperTest.cpp191
-rw-r--r--vmime-master/tests/net/folderAttributesTest.cpp137
-rw-r--r--vmime-master/tests/net/imap/IMAPCommandTest.cpp495
-rw-r--r--vmime-master/tests/net/imap/IMAPParserTest.cpp374
-rw-r--r--vmime-master/tests/net/imap/IMAPTagTest.cpp90
-rw-r--r--vmime-master/tests/net/imap/IMAPUtilsTest.cpp283
-rw-r--r--vmime-master/tests/net/maildir/maildirStoreTest.cpp584
-rw-r--r--vmime-master/tests/net/maildir/maildirUtilsTest.cpp54
-rw-r--r--vmime-master/tests/net/messageSetTest.cpp229
-rw-r--r--vmime-master/tests/net/pop3/POP3CommandTest.cpp241
-rw-r--r--vmime-master/tests/net/pop3/POP3ResponseTest.cpp244
-rw-r--r--vmime-master/tests/net/pop3/POP3StoreTest.cpp67
-rw-r--r--vmime-master/tests/net/pop3/POP3TestUtils.hpp69
-rw-r--r--vmime-master/tests/net/pop3/POP3UtilsTest.cpp88
-rw-r--r--vmime-master/tests/net/smtp/SMTPCommandSetTest.cpp181
-rw-r--r--vmime-master/tests/net/smtp/SMTPCommandTest.cpp252
-rw-r--r--vmime-master/tests/net/smtp/SMTPResponseTest.cpp238
-rw-r--r--vmime-master/tests/net/smtp/SMTPTransportTest.cpp324
-rw-r--r--vmime-master/tests/net/smtp/SMTPTransportTestUtils.hpp792
-rw-r--r--vmime-master/tests/parser/attachmentHelperTest.cpp335
-rw-r--r--vmime-master/tests/parser/bodyPartTest.cpp414
-rw-r--r--vmime-master/tests/parser/bodyTest.cpp79
-rw-r--r--vmime-master/tests/parser/charsetFilteredOutputStreamTest.cpp213
-rw-r--r--vmime-master/tests/parser/charsetTest.cpp252
-rw-r--r--vmime-master/tests/parser/charsetTestSuites.hpp102
-rw-r--r--vmime-master/tests/parser/datetimeTest.cpp123
-rw-r--r--vmime-master/tests/parser/dispositionTest.cpp150
-rw-r--r--vmime-master/tests/parser/emailAddressTest.cpp281
-rw-r--r--vmime-master/tests/parser/emptyContentHandlerTest.cpp99
-rw-r--r--vmime-master/tests/parser/fileContentHandlerTest.cpp134
-rw-r--r--vmime-master/tests/parser/headerFieldTest.cpp112
-rw-r--r--vmime-master/tests/parser/headerTest.cpp375
-rw-r--r--vmime-master/tests/parser/htmlTextPartTest.cpp241
-rw-r--r--vmime-master/tests/parser/mailboxGroupTest.cpp107
-rw-r--r--vmime-master/tests/parser/mailboxListTest.cpp47
-rw-r--r--vmime-master/tests/parser/mailboxTest.cpp187
-rw-r--r--vmime-master/tests/parser/mediaTypeTest.cpp100
-rw-r--r--vmime-master/tests/parser/messageIdSequenceTest.cpp78
-rw-r--r--vmime-master/tests/parser/messageIdTest.cpp77
-rw-r--r--vmime-master/tests/parser/messageTest.cpp64
-rw-r--r--vmime-master/tests/parser/parameterTest.cpp722
-rw-r--r--vmime-master/tests/parser/pathTest.cpp102
-rw-r--r--vmime-master/tests/parser/streamContentHandlerTest.cpp194
-rw-r--r--vmime-master/tests/parser/stringContentHandlerTest.cpp165
-rw-r--r--vmime-master/tests/parser/textTest.cpp918
-rw-r--r--vmime-master/tests/parser/wordEncoderTest.cpp174
-rw-r--r--vmime-master/tests/security/digest/md5Test.cpp228
-rw-r--r--vmime-master/tests/security/digest/sha1Test.cpp119
-rw-r--r--vmime-master/tests/testRunner.cpp305
-rw-r--r--vmime-master/tests/testUtils.cpp404
-rw-r--r--vmime-master/tests/testUtils.hpp407
-rw-r--r--vmime-master/tests/utility/datetimeUtilsTest.cpp157
-rw-r--r--vmime-master/tests/utility/encoder/b64EncoderTest.cpp168
-rw-r--r--vmime-master/tests/utility/encoder/encoderFactoryTest.cpp63
-rw-r--r--vmime-master/tests/utility/encoder/encoderTestUtils.hpp82
-rw-r--r--vmime-master/tests/utility/encoder/qpEncoderTest.cpp275
-rw-r--r--vmime-master/tests/utility/filteredStreamTest.cpp341
-rw-r--r--vmime-master/tests/utility/outputStreamByteArrayAdapterTest.cpp82
-rw-r--r--vmime-master/tests/utility/outputStreamSocketAdapterTest.cpp87
-rw-r--r--vmime-master/tests/utility/outputStreamStringAdapterTest.cpp84
-rw-r--r--vmime-master/tests/utility/parserInputStreamAdapterTest.cpp51
-rw-r--r--vmime-master/tests/utility/pathTest.cpp356
-rw-r--r--vmime-master/tests/utility/seekableInputStreamRegionAdapterTest.cpp176
-rw-r--r--vmime-master/tests/utility/stringUtilsTest.cpp214
-rw-r--r--vmime-master/tests/utility/urlTest.cpp312
65 files changed, 14689 insertions, 0 deletions
diff --git a/vmime-master/tests/misc/importanceHelperTest.cpp b/vmime-master/tests/misc/importanceHelperTest.cpp
new file mode 100644
index 0000000..d04d730
--- /dev/null
+++ b/vmime-master/tests/misc/importanceHelperTest.cpp
@@ -0,0 +1,191 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "tests/testUtils.hpp"
+
+#include "vmime/misc/importanceHelper.hpp"
+
+
+VMIME_TEST_SUITE_BEGIN(importanceHelperTest)
+
+ VMIME_TEST_LIST_BEGIN
+ VMIME_TEST(testResetImportance)
+
+ VMIME_TEST(testSetImportance1)
+ VMIME_TEST(testSetImportance2)
+ VMIME_TEST(testSetImportance3)
+ VMIME_TEST(testSetImportance4)
+ VMIME_TEST(testSetImportance5)
+
+ VMIME_TEST(testGetImportance1)
+ VMIME_TEST(testGetImportance2)
+ VMIME_TEST(testGetImportance3)
+ VMIME_TEST(testGetImportance4)
+ VMIME_TEST(testGetImportance5)
+ VMIME_TEST_LIST_END
+
+
+ // resetImportance
+
+ void testResetImportance() {
+
+ vmime::shared_ptr <vmime::header> hdr = vmime::make_shared <vmime::header>();
+
+ hdr->getField("Importance")->setValue("xxx");
+ hdr->getField("X-Priority")->setValue("yyy");
+
+ VASSERT_NO_THROW("1", hdr->findField("Importance"));
+ VASSERT_NO_THROW("2", hdr->findField("X-Priority"));
+
+ vmime::misc::importanceHelper::resetImportanceHeader(hdr);
+
+ VASSERT_NULL("3", hdr->findField("Importance"));
+ VASSERT_NULL("4", hdr->findField("X-Priority"));
+ }
+
+
+ // setImportance
+
+ void testSetImportanceImpl(
+ const vmime::misc::importanceHelper::Importance i,
+ const std::string& ImportanceValue,
+ const std::string& XPriorityValue
+ ) {
+
+ vmime::shared_ptr <vmime::header> hdr = vmime::make_shared <vmime::header>();
+
+ vmime::misc::importanceHelper::setImportanceHeader(hdr, i);
+
+ VASSERT_NO_THROW("1", hdr->findField("Importance"));
+ VASSERT_EQ("2", ImportanceValue, hdr->findField("Importance")->getValue()->generate());
+
+ VASSERT_NO_THROW("3", hdr->findField("X-Priority"));
+ VASSERT_EQ("4", XPriorityValue, hdr->findField("X-Priority")->getValue()->generate());
+ }
+
+ void testSetImportance1() {
+
+ testSetImportanceImpl(
+ vmime::misc::importanceHelper::IMPORTANCE_HIGHEST,
+ "high", "1 (Highest)"
+ );
+ }
+
+ void testSetImportance2() {
+
+ testSetImportanceImpl(
+ vmime::misc::importanceHelper::IMPORTANCE_HIGH,
+ "high", "2 (High)"
+ );
+ }
+
+ void testSetImportance3() {
+
+ testSetImportanceImpl(
+ vmime::misc::importanceHelper::IMPORTANCE_NORMAL,
+ "normal", "3 (Normal)"
+ );
+ }
+
+ void testSetImportance4() {
+
+ testSetImportanceImpl(
+ vmime::misc::importanceHelper::IMPORTANCE_LOW,
+ "low", "4 (Low)"
+ );
+ }
+
+ void testSetImportance5() {
+
+ testSetImportanceImpl(
+ vmime::misc::importanceHelper::IMPORTANCE_LOWEST,
+ "low", "5 (Lowest)"
+ );
+ }
+
+
+ // getImportance
+
+ void testGetImportanceImpl(
+ const vmime::misc::importanceHelper::Importance i1,
+ const vmime::misc::importanceHelper::Importance i2,
+ const std::string& ImportanceValue,
+ const std::string& XPriorityValue
+ ) {
+
+ vmime::shared_ptr <vmime::header> hdr1 = vmime::make_shared <vmime::header>();
+
+ hdr1->getField("Importance")->setValue(ImportanceValue);
+ VASSERT_EQ("1", i1, vmime::misc::importanceHelper::getImportanceHeader(hdr1));
+
+ vmime::shared_ptr <vmime::header> hdr2 = vmime::make_shared <vmime::header>();
+
+ hdr2->getField("X-Priority")->setValue(XPriorityValue);
+ VASSERT_EQ("2", i2, vmime::misc::importanceHelper::getImportanceHeader(hdr2));
+ }
+
+ void testGetImportance1() {
+
+ testGetImportanceImpl(
+ vmime::misc::importanceHelper::IMPORTANCE_HIGHEST,
+ vmime::misc::importanceHelper::IMPORTANCE_HIGHEST,
+ "high", "1 (Highest)");
+ }
+
+ void testGetImportance2() {
+
+ testGetImportanceImpl(
+ vmime::misc::importanceHelper::IMPORTANCE_HIGHEST,
+ vmime::misc::importanceHelper::IMPORTANCE_HIGH,
+ "high", "2 (High)"
+ );
+ }
+
+ void testGetImportance3() {
+
+ testGetImportanceImpl(
+ vmime::misc::importanceHelper::IMPORTANCE_NORMAL,
+ vmime::misc::importanceHelper::IMPORTANCE_NORMAL,
+ "normal", "3 (Normal)"
+ );
+ }
+
+ void testGetImportance4() {
+
+ testGetImportanceImpl(
+ vmime::misc::importanceHelper::IMPORTANCE_LOWEST,
+ vmime::misc::importanceHelper::IMPORTANCE_LOW,
+ "low", "4 (Low)"
+ );
+ }
+
+ void testGetImportance5() {
+
+ testGetImportanceImpl(
+ vmime::misc::importanceHelper::IMPORTANCE_LOWEST,
+ vmime::misc::importanceHelper::IMPORTANCE_LOWEST,
+ "low", "5 (Lowest)"
+ );
+ }
+
+VMIME_TEST_SUITE_END
diff --git a/vmime-master/tests/net/folderAttributesTest.cpp b/vmime-master/tests/net/folderAttributesTest.cpp
new file mode 100644
index 0000000..da0e025
--- /dev/null
+++ b/vmime-master/tests/net/folderAttributesTest.cpp
@@ -0,0 +1,137 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "tests/testUtils.hpp"
+
+#include "vmime/net/folderAttributes.hpp"
+
+
+VMIME_TEST_SUITE_BEGIN(folderAttributesTest)
+
+ VMIME_TEST_LIST_BEGIN
+ VMIME_TEST(testConstruct)
+ VMIME_TEST(testConstructCopy)
+ VMIME_TEST(testSetType)
+ VMIME_TEST(testSetFlags)
+ VMIME_TEST(testHasFlag)
+ VMIME_TEST(testSetUserFlags)
+ VMIME_TEST(testHasUserFlag)
+ VMIME_TEST(testSetSpecialUse)
+ VMIME_TEST_LIST_END
+
+
+ void testConstruct() {
+
+ vmime::net::folderAttributes attr;
+
+ // Default values
+ VASSERT_EQ("type", vmime::net::folderAttributes::TYPE_CONTAINS_FOLDERS
+ | vmime::net::folderAttributes::TYPE_CONTAINS_MESSAGES, attr.getType());
+ VASSERT_EQ("flags", 0, attr.getFlags());
+ VASSERT_EQ("user-flags", 0, attr.getUserFlags().size());
+ VASSERT_EQ("special-use", vmime::net::folderAttributes::SPECIALUSE_NONE, attr.getSpecialUse());
+ }
+
+ void testConstructCopy() {
+
+ std::vector <vmime::string> userFlags;
+ userFlags.push_back("\\XMyFlag1");
+ userFlags.push_back("\\XMyFlag2");
+ userFlags.push_back("\\XMyFlag3");
+
+ vmime::net::folderAttributes attr;
+
+ attr.setFlags(vmime::net::folderAttributes::FLAG_HAS_CHILDREN);
+ attr.setUserFlags(userFlags);
+
+ vmime::net::folderAttributes attr2(attr);
+
+ VASSERT("flags", attr2.getFlags() == attr.getFlags());
+ VASSERT("user-flags", attr2.getUserFlags() == attr.getUserFlags());
+ }
+
+ void testSetType() {
+
+ vmime::net::folderAttributes attr;
+ attr.setType(vmime::net::folderAttributes::TYPE_CONTAINS_FOLDERS);
+
+ VASSERT_EQ("eq", vmime::net::folderAttributes::TYPE_CONTAINS_FOLDERS, attr.getType());
+ }
+
+ void testSetFlags() {
+
+ vmime::net::folderAttributes attr;
+ attr.setFlags(vmime::net::folderAttributes::FLAG_HAS_CHILDREN);
+
+ VASSERT_EQ("eq", vmime::net::folderAttributes::FLAG_HAS_CHILDREN, attr.getFlags());
+ }
+
+ void testHasFlag() {
+
+ vmime::net::folderAttributes attr;
+ attr.setFlags(vmime::net::folderAttributes::FLAG_HAS_CHILDREN);
+
+ VASSERT("has", attr.hasFlag(vmime::net::folderAttributes::FLAG_HAS_CHILDREN));
+ VASSERT("has-not", !attr.hasFlag(vmime::net::folderAttributes::FLAG_NO_OPEN));
+ }
+
+ void testSetUserFlags() {
+
+ std::vector <vmime::string> userFlags;
+ userFlags.push_back("\\XMyFlag1");
+ userFlags.push_back("\\XMyFlag2");
+ userFlags.push_back("\\XMyFlag3");
+
+ vmime::net::folderAttributes attr;
+ attr.setUserFlags(userFlags);
+
+ VASSERT("eq", attr.getUserFlags() == userFlags);
+ }
+
+ void testHasUserFlag() {
+
+ std::vector <vmime::string> userFlags;
+ userFlags.push_back("\\XMyFlag1");
+ userFlags.push_back("\\XMyFlag2");
+ userFlags.push_back("\\XMyFlag3");
+
+ vmime::net::folderAttributes attr;
+ attr.setUserFlags(userFlags);
+
+ VASSERT("has", attr.hasUserFlag("\\XMyFlag1"));
+ VASSERT("has-casesensitive", !attr.hasUserFlag("\\xmyflag1"));
+ VASSERT("has-not", !attr.hasUserFlag("\\XMyFlag4"));
+ }
+
+ void testSetSpecialUse() {
+
+ const int use = vmime::net::folderAttributes::SPECIALUSE_JUNK
+ | vmime::net::folderAttributes::SPECIALUSE_TRASH;
+
+ vmime::net::folderAttributes attr;
+ attr.setSpecialUse(use);
+
+ VASSERT_EQ("eq", use, attr.getSpecialUse());
+ }
+
+VMIME_TEST_SUITE_END
diff --git a/vmime-master/tests/net/imap/IMAPCommandTest.cpp b/vmime-master/tests/net/imap/IMAPCommandTest.cpp
new file mode 100644
index 0000000..cf3446d
--- /dev/null
+++ b/vmime-master/tests/net/imap/IMAPCommandTest.cpp
@@ -0,0 +1,495 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "tests/testUtils.hpp"
+
+#include "vmime/net/imap/IMAPCommand.hpp"
+#include "vmime/net/imap/IMAPStore.hpp"
+#include "vmime/net/imap/IMAPConnection.hpp"
+
+
+using namespace vmime::net::imap;
+
+
+VMIME_TEST_SUITE_BEGIN(IMAPCommandTest)
+
+ VMIME_TEST_LIST_BEGIN
+ VMIME_TEST(testCreateCommand)
+ VMIME_TEST(testCreateCommandParams)
+ VMIME_TEST(testLOGIN)
+ VMIME_TEST(testAUTHENTICATE)
+ VMIME_TEST(testAUTHENTICATE_InitialResponse)
+ VMIME_TEST(testLIST)
+ VMIME_TEST(testSELECT)
+ VMIME_TEST(testSTATUS)
+ VMIME_TEST(testCREATE)
+ VMIME_TEST(testDELETE)
+ VMIME_TEST(testRENAME)
+ VMIME_TEST(testFETCH)
+ VMIME_TEST(testSTORE)
+ VMIME_TEST(testAPPEND)
+ VMIME_TEST(testCOPY)
+ VMIME_TEST(testSEARCH)
+ VMIME_TEST(testSTARTTLS)
+ VMIME_TEST(testCAPABILITY)
+ VMIME_TEST(testNOOP)
+ VMIME_TEST(testEXPUNGE)
+ VMIME_TEST(testCLOSE)
+ VMIME_TEST(testLOGOUT)
+ VMIME_TEST(testSend)
+ VMIME_TEST_LIST_END
+
+
+ void testCreateCommand() {
+
+ vmime::shared_ptr <IMAPCommand> cmd = IMAPCommand::createCommand("MY_COMMAND");
+
+ VASSERT_NOT_NULL("Not null", cmd);
+ VASSERT_EQ("Text", "MY_COMMAND", cmd->getText());
+ }
+
+ void testCreateCommandParams() {
+
+ vmime::shared_ptr <IMAPCommand> cmd = IMAPCommand::createCommand("MY_COMMAND param1 param2");
+
+ VASSERT_NOT_NULL("Not null", cmd);
+ VASSERT_EQ("Text", "MY_COMMAND param1 param2", cmd->getText());
+ }
+
+ void testLOGIN() {
+
+ vmime::shared_ptr <IMAPCommand> cmd = IMAPCommand::LOGIN("username", "password");
+
+ VASSERT_NOT_NULL("Not null", cmd);
+ VASSERT_EQ("Text", "LOGIN username password", cmd->getText());
+ VASSERT_EQ("Trace Text", "LOGIN {username} {password}", cmd->getTraceText());
+ }
+
+ void testAUTHENTICATE() {
+
+ vmime::shared_ptr <IMAPCommand> cmd = IMAPCommand::AUTHENTICATE("saslmechanism");
+
+ VASSERT_NOT_NULL("Not null", cmd);
+ VASSERT_EQ("Text", "AUTHENTICATE saslmechanism", cmd->getText());
+ }
+
+ void testAUTHENTICATE_InitialResponse() {
+
+ vmime::shared_ptr <IMAPCommand> cmd = IMAPCommand::AUTHENTICATE("saslmechanism", "initial-response");
+
+ VASSERT_NOT_NULL("Not null", cmd);
+ VASSERT_EQ("Text", "AUTHENTICATE saslmechanism initial-response", cmd->getText());
+ }
+
+ void testLIST() {
+
+ vmime::shared_ptr <IMAPCommand> cmd = IMAPCommand::LIST("ref-name", "mailbox-name");
+
+ VASSERT_NOT_NULL("Not null", cmd);
+ VASSERT_EQ("Text", "LIST ref-name mailbox-name", cmd->getText());
+
+ vmime::shared_ptr <IMAPCommand> cmdQuote = IMAPCommand::LIST("ref name", "mailbox-name");
+
+ VASSERT_NOT_NULL("Not null", cmdQuote);
+ VASSERT_EQ("Text", "LIST \"ref name\" mailbox-name", cmdQuote->getText());
+ }
+
+ void testSELECT() {
+
+ std::vector <vmime::string> params;
+ params.push_back("param-1");
+ params.push_back("param-2");
+
+
+ vmime::shared_ptr <IMAPCommand> cmdRO = IMAPCommand::SELECT(
+ /* readOnly */ true, "mailbox-name", std::vector <vmime::string>()
+ );
+
+ VASSERT_NOT_NULL("Not null", cmdRO);
+ VASSERT_EQ("Text", "EXAMINE mailbox-name", cmdRO->getText());
+
+ vmime::shared_ptr <IMAPCommand> cmdROQuote = IMAPCommand::SELECT(
+ /* readOnly */ true, "mailbox name", std::vector <vmime::string>()
+ );
+
+ VASSERT_NOT_NULL("Not null", cmdROQuote);
+ VASSERT_EQ("Text", "EXAMINE \"mailbox name\"", cmdROQuote->getText());
+
+
+ vmime::shared_ptr <IMAPCommand> cmdRW = IMAPCommand::SELECT(
+ /* readOnly */ false, "mailbox-name", std::vector <vmime::string>()
+ );
+
+ VASSERT_NOT_NULL("Not null", cmdRW);
+ VASSERT_EQ("Text", "SELECT mailbox-name", cmdRW->getText());
+
+ vmime::shared_ptr <IMAPCommand> cmdRWParams = IMAPCommand::SELECT(
+ /* readOnly */ false, "mailbox-name", params
+ );
+
+ VASSERT_NOT_NULL("Not null", cmdRWParams);
+ VASSERT_EQ("Text", "SELECT mailbox-name (param-1 param-2)", cmdRWParams->getText());
+
+ vmime::shared_ptr <IMAPCommand> cmdRWQuote = IMAPCommand::SELECT(
+ /* readOnly */ false, "mailbox name", std::vector <vmime::string>()
+ );
+
+ VASSERT_NOT_NULL("Not null", cmdRWQuote);
+ VASSERT_EQ("Text", "SELECT \"mailbox name\"", cmdRWQuote->getText());
+ }
+
+ void testSTATUS() {
+
+ std::vector <vmime::string> attribs;
+ attribs.push_back("attrib-1");
+ attribs.push_back("attrib-2");
+
+
+ vmime::shared_ptr <IMAPCommand> cmd =
+ IMAPCommand::STATUS("mailbox-name", attribs);
+
+ VASSERT_NOT_NULL("Not null", cmd);
+ VASSERT_EQ("Text", "STATUS mailbox-name (attrib-1 attrib-2)", cmd->getText());
+
+
+ vmime::shared_ptr <IMAPCommand> cmdQuote =
+ IMAPCommand::STATUS("mailbox name", attribs);
+
+ VASSERT_NOT_NULL("Not null", cmdQuote);
+ VASSERT_EQ("Text", "STATUS \"mailbox name\" (attrib-1 attrib-2)", cmdQuote->getText());
+ }
+
+ void testCREATE() {
+
+ std::vector <vmime::string> params;
+ params.push_back("param-1");
+ params.push_back("param-2");
+
+
+ vmime::shared_ptr <IMAPCommand> cmd =
+ IMAPCommand::CREATE("mailbox-name", params);
+
+ VASSERT_NOT_NULL("Not null", cmd);
+ VASSERT_EQ("Text", "CREATE mailbox-name (param-1 param-2)", cmd->getText());
+
+
+ vmime::shared_ptr <IMAPCommand> cmdQuote =
+ IMAPCommand::CREATE("mailbox name", params);
+
+ VASSERT_NOT_NULL("Not null", cmdQuote);
+ VASSERT_EQ("Text", "CREATE \"mailbox name\" (param-1 param-2)", cmdQuote->getText());
+
+
+ vmime::shared_ptr <IMAPCommand> cmdNoParam =
+ IMAPCommand::CREATE("mailbox-name", std::vector <vmime::string>());
+
+ VASSERT_NOT_NULL("Not null", cmdNoParam);
+ VASSERT_EQ("Text", "CREATE mailbox-name", cmdNoParam->getText());
+ }
+
+ void testDELETE() {
+
+ vmime::shared_ptr <IMAPCommand> cmd =
+ IMAPCommand::DELETE("mailbox-name");
+
+ VASSERT_NOT_NULL("Not null", cmd);
+ VASSERT_EQ("Text", "DELETE mailbox-name", cmd->getText());
+
+
+ vmime::shared_ptr <IMAPCommand> cmdQuote =
+ IMAPCommand::DELETE("mailbox name");
+
+ VASSERT_NOT_NULL("Not null", cmdQuote);
+ VASSERT_EQ("Text", "DELETE \"mailbox name\"", cmdQuote->getText());
+ }
+
+ void testRENAME() {
+
+ vmime::shared_ptr <IMAPCommand> cmd =
+ IMAPCommand::RENAME("mailbox-name", "new-mailbox-name");
+
+ VASSERT_NOT_NULL("Not null", cmd);
+ VASSERT_EQ("Text", "RENAME mailbox-name new-mailbox-name", cmd->getText());
+
+
+ vmime::shared_ptr <IMAPCommand> cmdQuote =
+ IMAPCommand::RENAME("mailbox name", "new mailbox name");
+
+ VASSERT_NOT_NULL("Not null", cmdQuote);
+ VASSERT_EQ("Text", "RENAME \"mailbox name\" \"new mailbox name\"", cmdQuote->getText());
+ }
+
+ void testFETCH() {
+
+ std::vector <vmime::string> params;
+ params.push_back("param-1");
+ params.push_back("param-2");
+
+
+ vmime::shared_ptr <IMAPCommand> cmdNum =
+ IMAPCommand::FETCH(vmime::net::messageSet::byNumber(42), params);
+
+ VASSERT_NOT_NULL("Not null", cmdNum);
+ VASSERT_EQ("Text", "FETCH 42 (param-1 param-2)", cmdNum->getText());
+
+
+ vmime::shared_ptr <IMAPCommand> cmdNums =
+ IMAPCommand::FETCH(vmime::net::messageSet::byNumber(42, 47), params);
+
+ VASSERT_NOT_NULL("Not null", cmdNums);
+ VASSERT_EQ("Text", "FETCH 42:47 (param-1 param-2)", cmdNums->getText());
+
+
+ vmime::shared_ptr <IMAPCommand> cmdUID =
+ IMAPCommand::FETCH(vmime::net::messageSet::byUID(42), params);
+
+ VASSERT_NOT_NULL("Not null", cmdUID);
+ VASSERT_EQ("Text", "UID FETCH 42 (param-1 param-2)", cmdUID->getText());
+
+
+ vmime::shared_ptr <IMAPCommand> cmdUIDs =
+ IMAPCommand::FETCH(vmime::net::messageSet::byUID(42, 47), params);
+
+ VASSERT_NOT_NULL("Not null", cmdUIDs);
+ VASSERT_EQ("Text", "UID FETCH 42:47 (param-1 param-2)", cmdUIDs->getText());
+ }
+
+ void testSTORE() {
+
+ std::vector <vmime::string> flags;
+ flags.push_back("flag-1");
+ flags.push_back("flag-2");
+
+
+ vmime::shared_ptr <IMAPCommand> cmdNum = IMAPCommand::STORE(
+ vmime::net::messageSet::byNumber(42), vmime::net::message::FLAG_MODE_SET, flags
+ );
+
+ VASSERT_NOT_NULL("Not null", cmdNum);
+ VASSERT_EQ("Text", "STORE 42 FLAGS (flag-1 flag-2)", cmdNum->getText());
+
+
+ vmime::shared_ptr <IMAPCommand> cmdNums = IMAPCommand::STORE(
+ vmime::net::messageSet::byNumber(42, 47), vmime::net::message::FLAG_MODE_SET, flags
+ );
+
+ VASSERT_NOT_NULL("Not null", cmdNums);
+ VASSERT_EQ("Text", "STORE 42:47 FLAGS (flag-1 flag-2)", cmdNums->getText());
+
+
+ vmime::shared_ptr <IMAPCommand> cmdUID = IMAPCommand::STORE(
+ vmime::net::messageSet::byUID(42), vmime::net::message::FLAG_MODE_SET, flags
+ );
+
+ VASSERT_NOT_NULL("Not null", cmdUID);
+ VASSERT_EQ("Text", "UID STORE 42 FLAGS (flag-1 flag-2)", cmdUID->getText());
+
+
+ vmime::shared_ptr <IMAPCommand> cmdUIDs = IMAPCommand::STORE(
+ vmime::net::messageSet::byUID(42, 47), vmime::net::message::FLAG_MODE_SET, flags
+ );
+
+ VASSERT_NOT_NULL("Not null", cmdUIDs);
+ VASSERT_EQ("Text", "UID STORE 42:47 FLAGS (flag-1 flag-2)", cmdUIDs->getText());
+
+
+ vmime::shared_ptr <IMAPCommand> cmdAdd = IMAPCommand::STORE(
+ vmime::net::messageSet::byUID(42, 47), vmime::net::message::FLAG_MODE_ADD, flags
+ );
+
+ VASSERT_NOT_NULL("Not null", cmdAdd);
+ VASSERT_EQ("Text", "UID STORE 42:47 +FLAGS (flag-1 flag-2)", cmdAdd->getText());
+
+
+ vmime::shared_ptr <IMAPCommand> cmdRem = IMAPCommand::STORE(
+ vmime::net::messageSet::byUID(42, 47), vmime::net::message::FLAG_MODE_REMOVE, flags
+ );
+
+ VASSERT_NOT_NULL("Not null", cmdRem);
+ VASSERT_EQ("Text", "UID STORE 42:47 -FLAGS (flag-1 flag-2)", cmdRem->getText());
+ }
+
+ void testAPPEND() {
+
+ std::vector <vmime::string> flags;
+ flags.push_back("flag-1");
+ flags.push_back("flag-2");
+
+
+ vmime::shared_ptr <IMAPCommand> cmd =
+ IMAPCommand::APPEND("mailbox-name", flags, /* date */ NULL, 1234);
+
+ VASSERT_NOT_NULL("Not null", cmd);
+ VASSERT_EQ("Text", "APPEND mailbox-name (flag-1 flag-2) {1234}", cmd->getText());
+
+
+ vmime::shared_ptr <IMAPCommand> cmdQuote =
+ IMAPCommand::APPEND("mailbox name", flags, /* date */ NULL, 1234);
+
+ VASSERT_NOT_NULL("Not null", cmdQuote);
+ VASSERT_EQ("Text", "APPEND \"mailbox name\" (flag-1 flag-2) {1234}", cmdQuote->getText());
+
+
+ vmime::datetime date(2014, 3, 15, 23, 11, 47, vmime::datetime::GMT2);
+ vmime::shared_ptr <IMAPCommand> cmdDate =
+ IMAPCommand::APPEND("mailbox name", flags, &date, 1234);
+
+ VASSERT_NOT_NULL("Not null", cmdDate);
+ VASSERT_EQ("Text", "APPEND \"mailbox name\" (flag-1 flag-2) \"15-Mar-2014 23:11:47 +0200\" {1234}", cmdDate->getText());
+ }
+
+ void testCOPY() {
+
+ vmime::shared_ptr <IMAPCommand> cmdNum =
+ IMAPCommand::COPY(vmime::net::messageSet::byNumber(42), "mailbox-name");
+
+ VASSERT_NOT_NULL("Not null", cmdNum);
+ VASSERT_EQ("Text", "COPY 42 mailbox-name", cmdNum->getText());
+
+
+ vmime::shared_ptr <IMAPCommand> cmdNums =
+ IMAPCommand::COPY(vmime::net::messageSet::byNumber(42, 47), "mailbox-name");
+
+ VASSERT_NOT_NULL("Not null", cmdNums);
+ VASSERT_EQ("Text", "COPY 42:47 mailbox-name", cmdNums->getText());
+
+
+ vmime::shared_ptr <IMAPCommand> cmdUID =
+ IMAPCommand::COPY(vmime::net::messageSet::byUID(42), "mailbox-name");
+
+ VASSERT_NOT_NULL("Not null", cmdUID);
+ VASSERT_EQ("Text", "UID COPY 42 mailbox-name", cmdUID->getText());
+
+
+ vmime::shared_ptr <IMAPCommand> cmdUIDs =
+ IMAPCommand::COPY(vmime::net::messageSet::byUID(42, 47), "mailbox-name");
+
+ VASSERT_NOT_NULL("Not null", cmdUIDs);
+ VASSERT_EQ("Text", "UID COPY 42:47 mailbox-name", cmdUIDs->getText());
+
+
+ vmime::shared_ptr <IMAPCommand> cmdQuote =
+ IMAPCommand::COPY(vmime::net::messageSet::byNumber(42, 47), "mailbox name");
+
+ VASSERT_NOT_NULL("Not null", cmdQuote);
+ VASSERT_EQ("Text", "COPY 42:47 \"mailbox name\"", cmdQuote->getText());
+ }
+
+ void testSEARCH() {
+
+ std::vector <vmime::string> searchKeys;
+ searchKeys.push_back("search-key-1");
+ searchKeys.push_back("search-key-2");
+
+ vmime::shared_ptr <IMAPCommand> cmd =
+ IMAPCommand::SEARCH(searchKeys, /* charset */ NULL);
+
+ VASSERT_NOT_NULL("Not null", cmd);
+ VASSERT_EQ("Text", "SEARCH search-key-1 search-key-2", cmd->getText());
+
+
+ vmime::charset cset("test-charset");
+
+ vmime::shared_ptr <IMAPCommand> cmdCset =
+ IMAPCommand::SEARCH(searchKeys, &cset);
+
+ VASSERT_NOT_NULL("Not null", cmdCset);
+ VASSERT_EQ("Text", "SEARCH CHARSET test-charset search-key-1 search-key-2", cmdCset->getText());
+ }
+
+ void testSTARTTLS() {
+
+ vmime::shared_ptr <IMAPCommand> cmd = IMAPCommand::STARTTLS();
+
+ VASSERT_NOT_NULL("Not null", cmd);
+ VASSERT_EQ("Text", "STARTTLS", cmd->getText());
+ }
+
+ void testCAPABILITY() {
+
+ vmime::shared_ptr <IMAPCommand> cmd = IMAPCommand::CAPABILITY();
+
+ VASSERT_NOT_NULL("Not null", cmd);
+ VASSERT_EQ("Text", "CAPABILITY", cmd->getText());
+ }
+
+ void testNOOP() {
+
+ vmime::shared_ptr <IMAPCommand> cmd = IMAPCommand::NOOP();
+
+ VASSERT_NOT_NULL("Not null", cmd);
+ VASSERT_EQ("Text", "NOOP", cmd->getText());
+ }
+
+ void testEXPUNGE() {
+
+ vmime::shared_ptr <IMAPCommand> cmd = IMAPCommand::EXPUNGE();
+
+ VASSERT_NOT_NULL("Not null", cmd);
+ VASSERT_EQ("Text", "EXPUNGE", cmd->getText());
+ }
+
+ void testCLOSE() {
+
+ vmime::shared_ptr <IMAPCommand> cmd = IMAPCommand::CLOSE();
+
+ VASSERT_NOT_NULL("Not null", cmd);
+ VASSERT_EQ("Text", "CLOSE", cmd->getText());
+ }
+
+ void testLOGOUT() {
+
+ vmime::shared_ptr <IMAPCommand> cmd = IMAPCommand::LOGOUT();
+
+ VASSERT_NOT_NULL("Not null", cmd);
+ VASSERT_EQ("Text", "LOGOUT", cmd->getText());
+ }
+
+ void testSend() {
+
+ vmime::shared_ptr <IMAPCommand> cmd =
+ IMAPCommand::createCommand("MY_COMMAND param1 param2");
+
+ vmime::shared_ptr <vmime::net::session> sess = vmime::net::session::create();
+
+ vmime::shared_ptr <vmime::security::authenticator> auth =
+ vmime::make_shared <vmime::security::defaultAuthenticator>();
+
+ vmime::shared_ptr <IMAPStore> store =
+ vmime::make_shared <IMAPStore>(sess, auth, /* secured */ false);
+
+ vmime::shared_ptr <IMAPConnection> conn =
+ vmime::make_shared <IMAPConnection>(store, auth);
+
+ vmime::shared_ptr <testSocket> sok = vmime::make_shared <testSocket>();
+ conn->setSocket(sok);
+
+ cmd->send(conn);
+
+ vmime::string response;
+ sok->localReceive(response);
+
+ VASSERT_EQ("Sent buffer", vmime::string(*conn->getTag()) + " MY_COMMAND param1 param2\r\n", response);
+ }
+
+VMIME_TEST_SUITE_END
diff --git a/vmime-master/tests/net/imap/IMAPParserTest.cpp b/vmime-master/tests/net/imap/IMAPParserTest.cpp
new file mode 100644
index 0000000..60ce16d
--- /dev/null
+++ b/vmime-master/tests/net/imap/IMAPParserTest.cpp
@@ -0,0 +1,374 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "tests/testUtils.hpp"
+
+#include "vmime/net/imap/IMAPTag.hpp"
+#include "vmime/net/imap/IMAPParser.hpp"
+
+
+VMIME_TEST_SUITE_BEGIN(IMAPParserTest)
+
+ VMIME_TEST_LIST_BEGIN
+ VMIME_TEST(testExtraSpaceInCapaResponse)
+ VMIME_TEST(testContinueReqWithoutSpace)
+ VMIME_TEST(testNILValueInBodyFldEnc)
+ VMIME_TEST(testFETCHResponse_optional_body_fld_lang)
+ VMIME_TEST(testFETCHBodyStructure_NIL_body_fld_param_value)
+ VMIME_TEST(testFETCHBodyStructure_empty_body_fld_param_instead_of_NIL)
+ VMIME_TEST(testPipelining)
+ VMIME_TEST(testStarFlagWithoutBackslash)
+ VMIME_TEST_LIST_END
+
+
+ // For Apple iCloud IMAP server
+ void testExtraSpaceInCapaResponse() {
+
+ const char* resp =
+ "* CAPABILITY IMAP4rev1 AUTH=ATOKEN AUTH=PLAIN \r\n" // extra space at end
+ "a001 OK Capability completed.\r\n";
+
+ // Strict mode
+ {
+ auto socket = vmime::make_shared <testSocket>();
+ socket->localSend(resp);
+
+ auto parser = vmime::make_shared <vmime::net::imap::IMAPParser>();
+ auto tag = vmime::make_shared <vmime::net::imap::IMAPTag>();
+
+ parser->setSocket(socket);
+ parser->setTimeoutHandler(vmime::make_shared <testTimeoutHandler>());
+ parser->setStrict(true);
+
+ VASSERT_THROW("strict mode", parser->readResponse(*tag), vmime::exceptions::invalid_response);
+ }
+
+ // Non-strict mode
+ {
+ auto socket = vmime::make_shared <testSocket>();
+ socket->localSend(resp);
+
+ auto parser = vmime::make_shared <vmime::net::imap::IMAPParser>();
+ auto tag = vmime::make_shared <vmime::net::imap::IMAPTag>();
+
+ parser->setSocket(socket);
+ parser->setTimeoutHandler(vmime::make_shared <testTimeoutHandler>());
+ parser->setStrict(false);
+
+ VASSERT_NO_THROW("non-strict mode", parser->readResponse(*tag));
+ }
+ }
+
+ // For Apple iCloud/Exchange IMAP server
+ void testContinueReqWithoutSpace() {
+
+ // continue_req ::= "+" SPACE (resp_text / base64)
+ //
+ // Some servers do not send SPACE when response text is empty.
+ // IMAP parser should allow this in non-strict mode.
+ //
+ // Eg:
+ //
+ // C: a002 AUTHENTICATE xxx[CR][LF]
+ // S: +[CR][LF]
+
+ vmime::shared_ptr <testSocket> socket = vmime::make_shared <testSocket>();
+ vmime::shared_ptr <vmime::net::timeoutHandler> toh = vmime::make_shared <testTimeoutHandler>();
+
+ vmime::shared_ptr <vmime::net::imap::IMAPTag> tag =
+ vmime::make_shared <vmime::net::imap::IMAPTag>();
+
+ socket->localSend("+\r\n");
+
+ vmime::shared_ptr <vmime::net::imap::IMAPParser> parser =
+ vmime::make_shared <vmime::net::imap::IMAPParser>();
+
+ parser->setSocket(socket);
+ parser->setTimeoutHandler(toh);
+
+ parser->setStrict(false);
+ VASSERT_NO_THROW("non-strict mode", parser->readResponse(*tag));
+
+ ++(*tag);
+
+ socket->localSend("+\r\n");
+
+ parser->setStrict(true);
+ VASSERT_THROW("strict mode", parser->readResponse(*tag), vmime::exceptions::invalid_response);
+ }
+
+ // When an IMAP4 client sends a FETCH (bodystructure) request to a server
+ // that is running the Exchange Server 2007 IMAP4 service, a corrupted
+ // response is sent as a reply
+ // --> http://support.microsoft.com/kb/975918/en-us
+ void testNILValueInBodyFldEnc() {
+
+ const char* resp = "* 7970 FETCH (UID 8036 FLAGS () BODYSTRUCTURE (\"text\" \"html\" (\"charset\" \"utf-8\") NIL NIL NIL 175501 1651 NIL NIL NIL NIL) RFC822.HEADER {3}\r\nx\r\n)\r\na001 OK FETCH complete\r\n";
+
+ // Strict mode
+ {
+ auto socket = vmime::make_shared <testSocket>();
+ socket->localSend(resp);
+
+ auto parser = vmime::make_shared <vmime::net::imap::IMAPParser>();
+ auto tag = vmime::make_shared <vmime::net::imap::IMAPTag>();
+
+ parser->setSocket(socket);
+ parser->setTimeoutHandler(vmime::make_shared <testTimeoutHandler>());
+ parser->setStrict(true);
+
+ VASSERT_THROW("strict mode", parser->readResponse(*tag), vmime::exceptions::invalid_response);
+ }
+
+ // Non-strict mode
+ {
+ auto socket = vmime::make_shared <testSocket>();
+ socket->localSend(resp);
+
+ auto parser = vmime::make_shared <vmime::net::imap::IMAPParser>();
+ auto tag = vmime::make_shared <vmime::net::imap::IMAPTag>();
+
+ parser->setSocket(socket);
+ parser->setTimeoutHandler(vmime::make_shared <testTimeoutHandler>());
+ parser->setStrict(false);
+
+ VASSERT_NO_THROW("non-strict mode", parser->readResponse(*tag));
+ }
+ }
+
+ // "body_fld_lang" is optional after "body_fld_dsp" in "body_ext_mpart" (Yahoo)
+ void testFETCHResponse_optional_body_fld_lang() {
+
+ vmime::shared_ptr <testSocket> socket = vmime::make_shared <testSocket>();
+ vmime::shared_ptr <vmime::net::timeoutHandler> toh = vmime::make_shared <testTimeoutHandler>();
+
+ vmime::shared_ptr <vmime::net::imap::IMAPTag> tag =
+ vmime::make_shared <vmime::net::imap::IMAPTag>();
+
+ const char* resp = "* 1 FETCH (UID 7 RFC822.SIZE 694142 BODYSTRUCTURE (((\"text\" \"plain\" (\"charset\" \"utf-8\") NIL NIL \"7bit\" 0 0 NIL NIL NIL NIL)(\"text\" \"html\" (\"charset\" \"utf-8\") NIL NIL \"7bit\" 193 0 NIL NIL NIL NIL) \"alternative\" (\"boundary\" \"----=_Part_536_109505883.1410847112666\") NIL)(\"image\" \"jpeg\" NIL \"<4db20d0e-e9f8-729b-aaf7-688b5956d0bc@yahoo.com>\" NIL \"base64\" 351784 NIL (\"attachment\" (\"name\" \"att2\" \"filename\" \"9.jpg\")) NIL NIL)(\"image\" \"jpeg\" NIL \"<542417d7-c0ed-db72-f9fc-d9ab2c7e0a6f@yahoo.com>\" NIL \"base64\" 337676 NIL (\"attachment\" (\"name\" \"att3\" \"filename\" \"10.jpg\")) NIL NIL) \"mixed\" (\"boundary\" \"----=_Part_537_1371134700.1410847112668\") NIL) RFC822.HEADER {3}\r\nx\r\n)\r\na001 OK FETCH complete\r\n";
+
+ socket->localSend(resp);
+
+ vmime::shared_ptr <vmime::net::imap::IMAPParser> parser =
+ vmime::make_shared <vmime::net::imap::IMAPParser>();
+
+ parser->setSocket(socket);
+ parser->setTimeoutHandler(toh);
+
+ VASSERT_NO_THROW("parse", parser->readResponse(*tag));
+ }
+
+ // Support for NIL boundary, for mail.ru IMAP server:
+ // https://www.ietf.org/mail-archive/web/imapext/current/msg05442.html
+ void testFETCHBodyStructure_NIL_body_fld_param_value() {
+
+ // ...("boundary" NIL)))... is an invalid syntax for a "body_fld_param_item"
+ const char* resp = "* 1 FETCH (BODYSTRUCTURE ((\"text\" \"plain\" (\"charset\" \"utf-8\") NIL NIL \"8bit\" 536 0 NIL NIL NIL NIL)(\"text\" \"html\" (\"charset\" \"utf-8\") NIL NIL \"8bit\" 7130 0 NIL NIL NIL NIL) \"alternative\" (\"boundary\" NIL)))\r\na001 OK FETCH complete\r\n";
+
+ // Strict mode
+ {
+ auto socket = vmime::make_shared <testSocket>();
+ socket->localSend(resp);
+
+ auto parser = vmime::make_shared <vmime::net::imap::IMAPParser>();
+ auto tag = vmime::make_shared <vmime::net::imap::IMAPTag>();
+
+ parser->setSocket(socket);
+ parser->setTimeoutHandler(vmime::make_shared <testTimeoutHandler>());
+ parser->setStrict(true);
+
+ VASSERT_THROW("strict mode", parser->readResponse(*tag), vmime::exceptions::invalid_response);
+ }
+
+ // Non-strict mode
+ {
+ auto socket = vmime::make_shared <testSocket>();
+ socket->localSend(resp);
+
+ auto parser = vmime::make_shared <vmime::net::imap::IMAPParser>();
+ auto tag = vmime::make_shared <vmime::net::imap::IMAPTag>();
+
+ parser->setSocket(socket);
+ parser->setTimeoutHandler(vmime::make_shared <testTimeoutHandler>());
+ parser->setStrict(false);
+
+ VASSERT_NO_THROW("non-strict mode", parser->readResponse(*tag));
+ }
+ }
+
+ void testFETCHBodyStructure_empty_body_fld_param_instead_of_NIL() {
+
+ const char* resp = "* 1 FETCH (BODYSTRUCTURE ((\"text\" \"html\" (\"charset\" \"cp1251\") NIL NIL \"base64\" 84056 0 NIL (\"inline\" NIL) NIL NIL)(\"image\" \"gif\" () \"25b2b55b5d97f04e9ea939fe32a46a65.gif\" NIL \"base64\" 20776 NIL (\"inline\" NIL) NIL NIL) \"related\" (\"boundary\" NIL)))\r\na001 OK FETCH complete\r\n";
+
+ // Strict mode
+ {
+ auto socket = vmime::make_shared <testSocket>();
+ socket->localSend(resp);
+
+ auto parser = vmime::make_shared <vmime::net::imap::IMAPParser>();
+ auto tag = vmime::make_shared <vmime::net::imap::IMAPTag>();
+
+ parser->setSocket(socket);
+ parser->setTimeoutHandler(vmime::make_shared <testTimeoutHandler>());
+ parser->setStrict(true);
+
+ VASSERT_THROW("strict mode", parser->readResponse(*tag), vmime::exceptions::invalid_response);
+ }
+
+ // Non-strict mode
+ {
+ auto socket = vmime::make_shared <testSocket>();
+ socket->localSend(resp);
+
+ auto parser = vmime::make_shared <vmime::net::imap::IMAPParser>();
+ auto tag = vmime::make_shared <vmime::net::imap::IMAPTag>();
+
+ parser->setSocket(socket);
+ parser->setTimeoutHandler(vmime::make_shared <testTimeoutHandler>());
+ parser->setStrict(false);
+
+ VASSERT_NO_THROW("non-strict mode", parser->readResponse(*tag));
+ }
+ }
+
+ // Test pipelined and out-of-order replies
+ void testPipelining() {
+
+ /*
+ [C] a001 SELECT "INBOX"
+ [C] a002 UID FETCH 42 (INTERNALDATE)
+ [C] a003 UID FETCH 43 (INTERNALDATE)
+ [S] * NO Error for a001
+ [S] a001 NO Access denied
+ [S] * NO Error for a003
+ [S] a003 BAD No mailbox selected
+ [S] * NO Error for a002
+ [S] a002 BAD No mailbox selected
+ */
+
+ vmime::shared_ptr <testSocket> socket = vmime::make_shared <testSocket>();
+ vmime::shared_ptr <vmime::net::timeoutHandler> toh = vmime::make_shared <testTimeoutHandler>();
+
+ vmime::net::imap::IMAPTag tag1; // a001
+ vmime::net::imap::IMAPTag tag2(tag1); // a002
+ ++tag2;
+ vmime::net::imap::IMAPTag tag3(tag2); // a003
+ ++tag3;
+
+ socket->localSend(
+ "* NO Error for a001\r\n"
+ "a001 NO Access denied\r\n"
+ "* NO Error for a003\r\n"
+ "a003 BAD No mailbox selected a003\r\n"
+ "* NO Error for a002\r\n"
+ "a002 BAD No mailbox selected a002\r\n"
+ );
+
+ vmime::shared_ptr <vmime::net::imap::IMAPParser> parser =
+ vmime::make_shared <vmime::net::imap::IMAPParser>();
+
+ parser->setSocket(socket);
+ parser->setTimeoutHandler(toh);
+
+ // Test response a001
+ vmime::scoped_ptr <vmime::net::imap::IMAPParser::response> resp1(parser->readResponse(tag1, /* literalHandler */ NULL));
+ VASSERT("a001 response", resp1);
+ VASSERT("a001 response_done", resp1->response_done);
+ VASSERT_EQ("a001 response tag", "a001", resp1->response_done->response_tagged->tag->tagString);
+ VASSERT_EQ("a001 response text", "Access denied", resp1->response_done->response_tagged->resp_cond_state->resp_text->text);
+ VASSERT_EQ("a001 resp_data.size()", 1, resp1->continue_req_or_response_data.size());
+ VASSERT("a001 resp_data[0]", resp1->continue_req_or_response_data[0]->response_data);
+ VASSERT("a001 resp_cond_state", resp1->continue_req_or_response_data[0]->response_data->resp_cond_state);
+ VASSERT_EQ("a001 resp_cond_state.text", "Error for a001", resp1->continue_req_or_response_data[0]->response_data->resp_cond_state->resp_text->text);
+ VASSERT_EQ("a001 resp_cond_state.status", vmime::net::imap::IMAPParser::resp_cond_state::NO, resp1->continue_req_or_response_data[0]->response_data->resp_cond_state->status);
+
+ // Test response a002
+ vmime::scoped_ptr <vmime::net::imap::IMAPParser::response> resp2(parser->readResponse(tag2, /* literalHandler */ NULL));
+ VASSERT("a002 response", resp2);
+ VASSERT("a002 response_done", resp2->response_done);
+ VASSERT_EQ("a002 response tag", "a002", resp2->response_done->response_tagged->tag->tagString);
+ VASSERT_EQ("a002 response text", "No mailbox selected a002", resp2->response_done->response_tagged->resp_cond_state->resp_text->text);
+ VASSERT_EQ("a002 resp_data.size()", 1, resp2->continue_req_or_response_data.size());
+ VASSERT("a002 resp_data[0]", resp2->continue_req_or_response_data[0]->response_data);
+ VASSERT("a002 resp_cond_state", resp2->continue_req_or_response_data[0]->response_data->resp_cond_state);
+ VASSERT_EQ("a002 resp_cond_state.text", "Error for a002", resp2->continue_req_or_response_data[0]->response_data->resp_cond_state->resp_text->text);
+ VASSERT_EQ("a002 resp_cond_state.status", vmime::net::imap::IMAPParser::resp_cond_state::NO, resp2->continue_req_or_response_data[0]->response_data->resp_cond_state->status);
+
+ // Test response a003
+ vmime::scoped_ptr <vmime::net::imap::IMAPParser::response> resp3(parser->readResponse(tag3, /* literalHandler */ NULL));
+ VASSERT("a003 response", resp3);
+ VASSERT("a003 response_done", resp3->response_done);
+ VASSERT_EQ("a003 response tag", "a003", resp3->response_done->response_tagged->tag->tagString);
+ VASSERT_EQ("a003 response text", "No mailbox selected a003", resp3->response_done->response_tagged->resp_cond_state->resp_text->text);
+ VASSERT_EQ("a003 resp_data.size()", 1, resp3->continue_req_or_response_data.size());
+ VASSERT("a003 resp_data[0]", resp3->continue_req_or_response_data[0]->response_data);
+ VASSERT("a003 resp_cond_state", resp3->continue_req_or_response_data[0]->response_data->resp_cond_state);
+ VASSERT_EQ("a003 resp_cond_state.text", "Error for a003", resp3->continue_req_or_response_data[0]->response_data->resp_cond_state->resp_text->text);
+ VASSERT_EQ("a003 resp_cond_state.status", vmime::net::imap::IMAPParser::resp_cond_state::NO, resp3->continue_req_or_response_data[0]->response_data->resp_cond_state->status);
+ }
+
+ // Some IMAP servers return "*" instead of "\*" in PERMANENTFLAGS
+ void testStarFlagWithoutBackslash() {
+
+ const char* resp =
+ "* OK [PERMANENTFLAGS (Answered Flagged Deleted Seen Draft *)] Flags permitted.\r\n"
+ "a001 OK Completed.\r\n";
+
+ // Strict mode
+ {
+ auto socket = vmime::make_shared <testSocket>();
+ auto toh = vmime::make_shared <testTimeoutHandler>();
+
+ auto tag = vmime::make_shared <vmime::net::imap::IMAPTag>();
+
+ socket->localSend(resp);
+
+ auto parser = vmime::make_shared <vmime::net::imap::IMAPParser>();
+
+ parser->setSocket(socket);
+ parser->setTimeoutHandler(toh);
+ parser->setStrict(true);
+
+ VASSERT_THROW("strict mode", parser->readResponse(*tag), vmime::exceptions::invalid_response);
+ }
+
+ // Non-strict mode
+ {
+ auto socket = vmime::make_shared <testSocket>();
+ auto toh = vmime::make_shared <testTimeoutHandler>();
+
+ auto tag = vmime::make_shared <vmime::net::imap::IMAPTag>();
+
+ socket->localSend(resp);
+
+ auto parser = vmime::make_shared <vmime::net::imap::IMAPParser>();
+
+ parser->setSocket(socket);
+ parser->setTimeoutHandler(toh);
+ parser->setStrict(false);
+
+ VASSERT_NO_THROW("non-strict mode", parser->readResponse(*tag));
+ }
+ }
+
+VMIME_TEST_SUITE_END
diff --git a/vmime-master/tests/net/imap/IMAPTagTest.cpp b/vmime-master/tests/net/imap/IMAPTagTest.cpp
new file mode 100644
index 0000000..c8e09b6
--- /dev/null
+++ b/vmime-master/tests/net/imap/IMAPTagTest.cpp
@@ -0,0 +1,90 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "tests/testUtils.hpp"
+
+#include "vmime/net/imap/IMAPTag.hpp"
+
+
+VMIME_TEST_SUITE_BEGIN(imapTagTest)
+
+ VMIME_TEST_LIST_BEGIN
+ VMIME_TEST(testConstruct)
+ VMIME_TEST(testIncrement)
+ VMIME_TEST(testReset)
+ VMIME_TEST(testNumber)
+ VMIME_TEST_LIST_END
+
+
+ void testConstruct() {
+
+ vmime::shared_ptr <vmime::net::imap::IMAPTag> tag =
+ vmime::make_shared <vmime::net::imap::IMAPTag>();
+
+ VASSERT_EQ("init", "a001", static_cast <vmime::string>(*tag));
+ }
+
+ void testIncrement() {
+
+ vmime::shared_ptr <vmime::net::imap::IMAPTag> tag =
+ vmime::make_shared <vmime::net::imap::IMAPTag>();
+
+ (*tag)++;
+ VASSERT_EQ("init", "a002", static_cast <vmime::string>(*tag));
+
+ (*tag)++;
+ VASSERT_EQ("init", "a003", static_cast <vmime::string>(*tag));
+
+ (*tag)++;
+ VASSERT_EQ("init", "a004", static_cast <vmime::string>(*tag));
+ }
+
+ void testReset() {
+
+ vmime::shared_ptr <vmime::net::imap::IMAPTag> tag =
+ vmime::make_shared <vmime::net::imap::IMAPTag>();
+
+ for (int i = tag->number() ; i < tag->maximumNumber() ; ++i) {
+ (*tag)++;
+ }
+
+ VASSERT_EQ("last", "Z999", static_cast <vmime::string>(*tag));
+
+ (*tag)++;
+
+ VASSERT_EQ("reset", "a001", static_cast <vmime::string>(*tag));
+ }
+
+ void testNumber() {
+
+ vmime::shared_ptr <vmime::net::imap::IMAPTag> tag =
+ vmime::make_shared <vmime::net::imap::IMAPTag>();
+
+ for (int i = 0 ; i < 41 ; ++i) {
+ (*tag)++;
+ }
+
+ VASSERT_EQ("number", 42, tag->number());
+ }
+
+VMIME_TEST_SUITE_END
diff --git a/vmime-master/tests/net/imap/IMAPUtilsTest.cpp b/vmime-master/tests/net/imap/IMAPUtilsTest.cpp
new file mode 100644
index 0000000..b707fd0
--- /dev/null
+++ b/vmime-master/tests/net/imap/IMAPUtilsTest.cpp
@@ -0,0 +1,283 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "tests/testUtils.hpp"
+
+#include "vmime/net/imap/IMAPUtils.hpp"
+#include "vmime/net/imap/IMAPParser.hpp"
+
+
+using namespace vmime::net::imap;
+
+
+
+VMIME_TEST_SUITE_BEGIN(IMAPUtilsTest)
+
+ VMIME_TEST_LIST_BEGIN
+ VMIME_TEST(testQuoteString)
+ VMIME_TEST(testToModifiedUTF7)
+ VMIME_TEST(testFromModifiedUTF7)
+ VMIME_TEST(testConvertAddressList)
+ VMIME_TEST(testMessageFlagList)
+ VMIME_TEST(testDateTime)
+ VMIME_TEST(testPathToString)
+ VMIME_TEST(testStringToPath)
+ VMIME_TEST(testBuildFetchCommand)
+ VMIME_TEST_LIST_END
+
+
+ void testQuoteString() {
+
+ VASSERT_EQ("unquoted", "ascii", IMAPUtils::quoteString("ascii"));
+ VASSERT_EQ("space", "\"ascii with space\"", IMAPUtils::quoteString("ascii with space"));
+
+ VASSERT_EQ("special1", "\"(\"", IMAPUtils::quoteString("("));
+ VASSERT_EQ("special2", "\")\"", IMAPUtils::quoteString(")"));
+ VASSERT_EQ("special3", "\"{\"", IMAPUtils::quoteString("{"));
+ VASSERT_EQ("special4", "\" \"", IMAPUtils::quoteString(" "));
+ VASSERT_EQ("special5", "\"%\"", IMAPUtils::quoteString("%"));
+ VASSERT_EQ("special6", "\"*\"", IMAPUtils::quoteString("*"));
+ VASSERT_EQ("special7", "\"\\\"\"", IMAPUtils::quoteString("\""));
+ VASSERT_EQ("special8", "\"\\\\\"", IMAPUtils::quoteString("\\"));
+ VASSERT_EQ("special9", "\"\x7f\"", IMAPUtils::quoteString("\x7f"));
+
+ }
+
+ void testToModifiedUTF7() {
+
+ #define FC(x) vmime::net::folder::path::component(x, vmime::charsets::UTF_8)
+
+ // Example strings from RFC-1642 (modified for IMAP UTF-7)
+ VASSERT_EQ("1", "A&ImIDkQ-.", IMAPUtils::toModifiedUTF7('/', FC("A\xe2\x89\xa2\xce\x91.")));
+ VASSERT_EQ("2", "Hi Mum &Jjo-!", IMAPUtils::toModifiedUTF7('/', FC("Hi Mum \xe2\x98\xba!")));
+ VASSERT_EQ("3", "&ZeVnLIqe-", IMAPUtils::toModifiedUTF7('/', FC("\xe6\x97\xa5\xe6\x9c\xac\xe8\xaa\x9e")));
+ VASSERT_EQ("4", "Item 3 is &AKM- 1.", IMAPUtils::toModifiedUTF7('/', FC("Item 3 is \xc2\xa3 1.")));
+
+ VASSERT_EQ("escape char", "&-", IMAPUtils::toModifiedUTF7('/', FC("&")));
+ VASSERT_EQ("ascii", "plain ascii text", IMAPUtils::toModifiedUTF7('/', FC("plain ascii text")));
+ VASSERT_EQ("special", "!\"#$%*+-;<=>@[]^_`{|}", IMAPUtils::toModifiedUTF7('/', FC("!\"#$%*+-;<=>@[]^_`{|}")));
+
+ #undef FC
+ }
+
+ void testFromModifiedUTF7() {
+
+ #define FC(x) vmime::net::folder::path::component(x, vmime::charsets::UTF_8)
+
+ // Example strings from RFC-1642 (modified for IMAP UTF-7)
+ VASSERT_EQ("1", FC("A\xe2\x89\xa2\xce\x91."), IMAPUtils::fromModifiedUTF7("A&ImIDkQ-."));
+ VASSERT_EQ("2", FC("Hi Mum \xe2\x98\xba!"), IMAPUtils::fromModifiedUTF7("Hi Mum &Jjo-!"));
+ VASSERT_EQ("3", FC("\xe6\x97\xa5\xe6\x9c\xac\xe8\xaa\x9e"), IMAPUtils::fromModifiedUTF7("&ZeVnLIqe-"));
+ VASSERT_EQ("4", FC("Item 3 is \xc2\xa3 1."), IMAPUtils::fromModifiedUTF7("Item 3 is &AKM- 1."));
+
+ VASSERT_EQ("escape char", FC("&"), IMAPUtils::fromModifiedUTF7("&-"));
+ VASSERT_EQ("ascii", FC("plain ascii text"), IMAPUtils::fromModifiedUTF7("plain ascii text"));
+ VASSERT_EQ("special", FC("!\"#$%*+;<=>@[]^_`{|}"), IMAPUtils::fromModifiedUTF7("!\"#$%*+-;<=>@[]^_`{|}"));
+
+ #undef FC
+ }
+
+ void testConvertAddressList() {
+
+ IMAPParser parser;
+ IMAPParser::address_list addrList;
+
+ vmime::string line("((\"name\" NIL \"mailbox\" \"host\")(\"name2\" NIL \"mailbox2\" \"host2\"))");
+ vmime::size_t pos = 0;
+
+ VASSERT("parse", addrList.parseImpl(parser, line, &pos));
+
+ vmime::mailboxList mboxList;
+ IMAPUtils::convertAddressList(addrList, mboxList);
+
+ VASSERT_EQ("mbox-count", 2, mboxList.getMailboxCount());
+ VASSERT_EQ("mbox-1", "mailbox@host", mboxList.getMailboxAt(0)->getEmail().toString());
+ VASSERT_EQ("mbox-1", "name", mboxList.getMailboxAt(0)->getName().getWholeBuffer());
+ VASSERT_EQ("mbox-2", "mailbox2@host2", mboxList.getMailboxAt(1)->getEmail().toString());
+ VASSERT_EQ("mbox-2", "name2", mboxList.getMailboxAt(1)->getName().getWholeBuffer());
+ }
+
+ void testMessageFlagList() {
+
+ int flags = 0;
+ std::vector <vmime::string> flagList;
+
+ // Test each flag
+ flags = vmime::net::message::FLAG_REPLIED;
+ flagList = IMAPUtils::messageFlagList(flags);
+ VASSERT("replied", std::find(flagList.begin(), flagList.end(), "\\Answered") != flagList.end());
+
+ flags = vmime::net::message::FLAG_MARKED;
+ flagList = IMAPUtils::messageFlagList(flags);
+ VASSERT("marked", std::find(flagList.begin(), flagList.end(), "\\Flagged") != flagList.end());
+
+ flags = vmime::net::message::FLAG_DELETED;
+ flagList = IMAPUtils::messageFlagList(flags);
+ VASSERT("deleted", std::find(flagList.begin(), flagList.end(), "\\Deleted") != flagList.end());
+
+ flags = vmime::net::message::FLAG_SEEN;
+ flagList = IMAPUtils::messageFlagList(flags);
+ VASSERT("seen", std::find(flagList.begin(), flagList.end(), "\\Seen") != flagList.end());
+
+ flags = vmime::net::message::FLAG_DRAFT;
+ flagList = IMAPUtils::messageFlagList(flags);
+ VASSERT("draft", std::find(flagList.begin(), flagList.end(), "\\Draft") != flagList.end());
+
+ // Multiple flags
+ flags = vmime::net::message::FLAG_REPLIED;
+ flagList = IMAPUtils::messageFlagList(flags);
+
+ VASSERT_EQ("1.size", 1, flagList.size());
+ VASSERT("1.found", std::find(flagList.begin(), flagList.end(), "\\Answered") != flagList.end());
+
+ flags |= vmime::net::message::FLAG_SEEN;
+ flagList = IMAPUtils::messageFlagList(flags);
+
+ VASSERT_EQ("2.size", 2, flagList.size());
+ VASSERT("2.found1", std::find(flagList.begin(), flagList.end(), "\\Answered") != flagList.end());
+ VASSERT("2.found2", std::find(flagList.begin(), flagList.end(), "\\Seen") != flagList.end());
+ }
+
+ void testDateTime() {
+
+ vmime::datetime dt(2014, 3, 17, 23, 26, 22, vmime::datetime::GMT2);
+ VASSERT_EQ("datetime", "\"17-Mar-2014 23:26:22 +0200\"", IMAPUtils::dateTime(dt));
+ }
+
+ void testPathToString() {
+
+ #define FC(x) vmime::net::folder::path::component(x, vmime::charsets::UTF_8)
+
+ vmime::net::folder::path path;
+ path /= FC("Hi Mum \xe2\x98\xba!");
+ path /= FC("\xe6\x97\xa5\xe6\x9c\xac\xe8\xaa\x9e");
+
+ VASSERT_EQ("string", "Hi Mum &Jjo-!/&ZeVnLIqe-", IMAPUtils::pathToString('/', path));
+
+ #undef FC
+ }
+
+ void testStringToPath() {
+
+ #define FC(x) vmime::net::folder::path::component(x, vmime::charsets::UTF_8)
+
+ vmime::net::folder::path path = IMAPUtils::stringToPath('/', "Hi Mum &Jjo-!/&ZeVnLIqe-");
+
+ VASSERT_EQ("count", 2, path.getSize());
+ VASSERT_EQ("component1", FC("Hi Mum \xe2\x98\xba!"), path[0]);
+ VASSERT_EQ("component2", FC("\xe6\x97\xa5\xe6\x9c\xac\xe8\xaa\x9e"), path[1]);
+
+ #undef FC
+ }
+
+ void testBuildFetchCommand() {
+
+ vmime::shared_ptr <IMAPConnection> cnt;
+ vmime::net::messageSet msgs = vmime::net::messageSet::byNumber(42);
+
+ // SIZE
+ {
+ vmime::net::fetchAttributes attribs = vmime::net::fetchAttributes::SIZE;
+
+ vmime::shared_ptr <IMAPCommand> cmd = IMAPUtils::buildFetchCommand(cnt, msgs, attribs);
+ VASSERT_EQ("size", "FETCH 42 RFC822.SIZE", cmd->getText());
+ }
+
+ // FLAGS
+ {
+ vmime::net::fetchAttributes attribs = vmime::net::fetchAttributes::FLAGS;
+
+ vmime::shared_ptr <IMAPCommand> cmd = IMAPUtils::buildFetchCommand(cnt, msgs, attribs);
+ VASSERT_EQ("flags", "FETCH 42 FLAGS", cmd->getText());
+ }
+
+ // STRUCTURE
+ {
+ vmime::net::fetchAttributes attribs = vmime::net::fetchAttributes::STRUCTURE;
+
+ vmime::shared_ptr <IMAPCommand> cmd = IMAPUtils::buildFetchCommand(cnt, msgs, attribs);
+ VASSERT_EQ("structure", "FETCH 42 BODYSTRUCTURE", cmd->getText());
+ }
+
+ // UID
+ {
+ vmime::net::fetchAttributes attribs = vmime::net::fetchAttributes::UID;
+
+ vmime::shared_ptr <IMAPCommand> cmd = IMAPUtils::buildFetchCommand(cnt, msgs, attribs);
+ VASSERT_EQ("uid", "FETCH 42 UID", cmd->getText());
+ }
+
+ // ENVELOPE
+ {
+ vmime::net::fetchAttributes attribs = vmime::net::fetchAttributes::ENVELOPE;
+
+ vmime::shared_ptr <IMAPCommand> cmd = IMAPUtils::buildFetchCommand(cnt, msgs, attribs);
+ VASSERT_EQ("envelope", "FETCH 42 ENVELOPE", cmd->getText());
+ }
+
+ // CONTENT_INFO
+ {
+ vmime::net::fetchAttributes attribs = vmime::net::fetchAttributes::CONTENT_INFO;
+
+ vmime::shared_ptr <IMAPCommand> cmd = IMAPUtils::buildFetchCommand(cnt, msgs, attribs);
+ VASSERT_EQ("content", "FETCH 42 BODY[HEADER.FIELDS (CONTENT_TYPE)]", cmd->getText());
+ }
+
+ // IMPORTANCE
+ {
+ vmime::net::fetchAttributes attribs = vmime::net::fetchAttributes::IMPORTANCE;
+
+ vmime::shared_ptr <IMAPCommand> cmd = IMAPUtils::buildFetchCommand(cnt, msgs, attribs);
+ VASSERT_EQ("importance", "FETCH 42 BODY[HEADER.FIELDS (IMPORTANCE X-PRIORITY)]", cmd->getText());
+ }
+
+ // Any header attribute + full header should give RFC822.HEADER
+ {
+ vmime::net::fetchAttributes attribs;
+ attribs.add(vmime::net::fetchAttributes::ENVELOPE);
+ attribs.add(vmime::net::fetchAttributes::FULL_HEADER);
+
+ vmime::shared_ptr <IMAPCommand> cmd = IMAPUtils::buildFetchCommand(cnt, msgs, attribs);
+ VASSERT_EQ("full-header", "FETCH 42 RFC822.HEADER", cmd->getText());
+ }
+
+ // Test custom header
+ {
+ vmime::net::fetchAttributes attribs;
+ attribs.add("X-MyHeader");
+
+ vmime::shared_ptr <IMAPCommand> cmd = IMAPUtils::buildFetchCommand(cnt, msgs, attribs);
+ VASSERT_EQ("custom-header", "FETCH 42 BODY[HEADER.FIELDS (x-myheader)]", cmd->getText());
+ }
+
+ // Test multiple flags
+ {
+ vmime::net::fetchAttributes attribs =
+ vmime::net::fetchAttributes::UID | vmime::net::fetchAttributes::FLAGS;
+
+ vmime::shared_ptr <IMAPCommand> cmd = IMAPUtils::buildFetchCommand(cnt, msgs, attribs);
+ VASSERT_EQ("multiple", "FETCH 42 (FLAGS UID)", cmd->getText());
+ }
+ }
+
+VMIME_TEST_SUITE_END
diff --git a/vmime-master/tests/net/maildir/maildirStoreTest.cpp b/vmime-master/tests/net/maildir/maildirStoreTest.cpp
new file mode 100644
index 0000000..1f418e8
--- /dev/null
+++ b/vmime-master/tests/net/maildir/maildirStoreTest.cpp
@@ -0,0 +1,584 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "tests/testUtils.hpp"
+
+#include "vmime/platform.hpp"
+
+#include "vmime/net/maildir/maildirStore.hpp"
+#include "vmime/net/maildir/maildirFormat.hpp"
+
+
+// Shortcuts and helpers
+typedef vmime::utility::file::path fspath;
+typedef vmime::utility::file::path::component fspathc;
+
+typedef vmime::net::folder::path fpath;
+typedef vmime::net::folder::path::component fpathc;
+
+
+const fpath operator/(const fpath& path, const std::string& c) {
+
+ return path / fpathc(c);
+}
+
+
+/** Test messages */
+static const vmime::string TEST_MESSAGE_1 =
+ "From: <test@vmime.org>\r\n"
+ "Subject: VMime Test\r\n"
+ "Date: Thu, 01 Mar 2007 09:49:35 +0100\r\n"
+ "\r\n"
+ "Hello, world!";
+
+
+/** Maildir trees used in tests.
+ * Structure:
+ *
+ * .
+ * |-- Folder
+ * | `-- SubFolder
+ * | |-- SubSubFolder1
+ * | `-- SubSubFolder2
+ * `-- Folder2
+ *
+ */
+
+// KMail format
+static const vmime::string TEST_MAILDIR_KMAIL[] = { // directories to create
+ "/Folder",
+ "/Folder/new",
+ "/Folder/tmp",
+ "/Folder/cur",
+ "/.Folder.directory",
+ "/.Folder.directory/SubFolder",
+ "/.Folder.directory/SubFolder/new",
+ "/.Folder.directory/SubFolder/tmp",
+ "/.Folder.directory/SubFolder/cur",
+ "/.Folder.directory/.SubFolder.directory",
+ "/.Folder.directory/.SubFolder.directory/SubSubFolder1",
+ "/.Folder.directory/.SubFolder.directory/SubSubFolder1/new",
+ "/.Folder.directory/.SubFolder.directory/SubSubFolder1/tmp",
+ "/.Folder.directory/.SubFolder.directory/SubSubFolder1/cur",
+ "/.Folder.directory/.SubFolder.directory/SubSubFolder2",
+ "/.Folder.directory/.SubFolder.directory/SubSubFolder2/new",
+ "/.Folder.directory/.SubFolder.directory/SubSubFolder2/tmp",
+ "/.Folder.directory/.SubFolder.directory/SubSubFolder2/cur",
+ "/Folder2",
+ "/Folder2/new",
+ "/Folder2/tmp",
+ "/Folder2/cur",
+ "*" // end
+};
+
+static const vmime::string TEST_MAILDIRFILES_KMAIL[] = { // files to create and their contents
+ "/.Folder.directory/.SubFolder.directory/SubSubFolder2/cur/1043236113.351.EmqD:S", TEST_MESSAGE_1,
+ "*" // end
+};
+
+// Courier format
+static const vmime::string TEST_MAILDIR_COURIER[] = { // directories to create
+ "/.Folder",
+ "/.Folder/new",
+ "/.Folder/tmp",
+ "/.Folder/cur",
+ "/.Folder.SubFolder",
+ "/.Folder.SubFolder",
+ "/.Folder.SubFolder/new",
+ "/.Folder.SubFolder/tmp",
+ "/.Folder.SubFolder/cur",
+ "/.Folder.SubFolder.SubSubFolder1",
+ "/.Folder.SubFolder.SubSubFolder1/new",
+ "/.Folder.SubFolder.SubSubFolder1/tmp",
+ "/.Folder.SubFolder.SubSubFolder1/cur",
+ "/.Folder.SubFolder.SubSubFolder2",
+ "/.Folder.SubFolder.SubSubFolder2/new",
+ "/.Folder.SubFolder.SubSubFolder2/tmp",
+ "/.Folder.SubFolder.SubSubFolder2/cur",
+ "/.Folder2",
+ "/.Folder2/new",
+ "/.Folder2/tmp",
+ "/.Folder2/cur",
+ "*" // end
+};
+
+static const vmime::string TEST_MAILDIRFILES_COURIER[] = { // files to create and their contents
+ "/.Folder/maildirfolder", "",
+ "/.Folder.SubFolder/maildirfolder", "",
+ "/.Folder.SubFolder.SubSubFolder1/maildirfolder", "",
+ "/.Folder.SubFolder.SubSubFolder2/maildirfolder", "",
+ "/.Folder.SubFolder.SubSubFolder2/cur/1043236113.351.EmqD:S", TEST_MESSAGE_1,
+ "/.Folder2/maildirfolder", "",
+ "*" // end
+};
+
+
+
+VMIME_TEST_SUITE_BEGIN(maildirStoreTest)
+
+ VMIME_TEST_LIST_BEGIN
+ VMIME_TEST(testDetectFormat_KMail)
+ VMIME_TEST(testDetectFormat_Courier)
+
+ VMIME_TEST(testListRootFolders_KMail)
+ VMIME_TEST(testListAllFolders_KMail)
+
+ VMIME_TEST(testListRootFolders_Courier)
+ VMIME_TEST(testListAllFolders_Courier)
+
+ VMIME_TEST(testListMessages_KMail)
+ VMIME_TEST(testListMessages_Courier)
+
+ VMIME_TEST(testRenameFolder_KMail)
+ VMIME_TEST(testRenameFolder_Courier)
+
+ VMIME_TEST(testDestroyFolder_KMail)
+ VMIME_TEST(testDestroyFolder_Courier)
+
+ VMIME_TEST(testFolderExists_KMail)
+ VMIME_TEST(testFolderExists_Courier)
+
+ VMIME_TEST(testCreateFolder_KMail)
+ VMIME_TEST(testCreateFolder_Courier)
+ VMIME_TEST_LIST_END
+
+
+public:
+
+ maildirStoreTest() {
+
+ // Temporary directory
+ m_tempPath = fspath() / fspathc("tmp") // Use /tmp
+ / fspathc("vmime" + vmime::utility::stringUtils::toString(std::time(NULL))
+ + vmime::utility::stringUtils::toString(std::rand()));
+ }
+
+ void tearDown() {
+
+ // In case of an uncaught exception
+ destroyMaildir();
+ }
+
+ void testDetectFormat_KMail() {
+
+ createMaildir(TEST_MAILDIR_KMAIL, TEST_MAILDIRFILES_KMAIL);
+
+ vmime::shared_ptr <vmime::net::maildir::maildirStore> store =
+ vmime::dynamicCast <vmime::net::maildir::maildirStore>(createAndConnectStore());
+
+ VASSERT_EQ("*", "kmail", store->getFormat()->getName());
+
+ destroyMaildir();
+ }
+
+ void testDetectFormat_Courier() {
+
+ createMaildir(TEST_MAILDIR_COURIER, TEST_MAILDIRFILES_COURIER);
+
+ vmime::shared_ptr <vmime::net::maildir::maildirStore> store =
+ vmime::dynamicCast <vmime::net::maildir::maildirStore>(createAndConnectStore());
+
+ VASSERT_EQ("*", "courier", store->getFormat()->getName());
+
+ destroyMaildir();
+ }
+
+
+ void testListRootFolders_KMail() {
+
+ testListRootFoldersImpl(TEST_MAILDIR_KMAIL, TEST_MAILDIRFILES_KMAIL);
+ }
+
+ void testListRootFolders_Courier() {
+
+ testListRootFoldersImpl(TEST_MAILDIR_COURIER, TEST_MAILDIRFILES_COURIER);
+ }
+
+ void testListRootFoldersImpl(const vmime::string* const dirs, const vmime::string* const files) {
+
+ createMaildir(dirs, files);
+
+ // Connect to store
+ vmime::shared_ptr <vmime::net::store> store = createAndConnectStore();
+ vmime::shared_ptr <vmime::net::folder> rootFolder = store->getRootFolder();
+
+ // Get root folders, not recursive
+ const std::vector <vmime::shared_ptr <vmime::net::folder> >
+ rootFolders = rootFolder->getFolders(false);
+
+ VASSERT_EQ("1", 2, rootFolders.size());
+ VASSERT("2", findFolder(rootFolders, fpath() / "Folder") != NULL);
+ VASSERT("3", findFolder(rootFolders, fpath() / "Folder2") != NULL);
+
+ destroyMaildir();
+ }
+
+
+ void testListAllFolders_KMail() {
+
+ testListAllFoldersImpl(TEST_MAILDIR_KMAIL, TEST_MAILDIRFILES_KMAIL);
+ }
+
+ void testListAllFolders_Courier() {
+
+ testListAllFoldersImpl(TEST_MAILDIR_COURIER, TEST_MAILDIRFILES_COURIER);
+ }
+
+ void testListAllFoldersImpl(const vmime::string* const dirs, const vmime::string* const files) {
+
+ createMaildir(dirs, files);
+
+ // Connect to store
+ vmime::shared_ptr <vmime::net::store> store = createAndConnectStore();
+ vmime::shared_ptr <vmime::net::folder> rootFolder = store->getRootFolder();
+
+ // Get all folders, recursive
+ const std::vector <vmime::shared_ptr <vmime::net::folder> >
+ allFolders = rootFolder->getFolders(true);
+
+ VASSERT_EQ("1", 5, allFolders.size());
+ VASSERT("2", findFolder(allFolders, fpath() / "Folder") != NULL);
+ VASSERT("3", findFolder(allFolders, fpath() / "Folder" / "SubFolder") != NULL);
+ VASSERT("4", findFolder(allFolders, fpath() / "Folder" / "SubFolder" / "SubSubFolder1") != NULL);
+ VASSERT("5", findFolder(allFolders, fpath() / "Folder" / "SubFolder" / "SubSubFolder2") != NULL);
+ VASSERT("6", findFolder(allFolders, fpath() / "Folder2") != NULL);
+
+ destroyMaildir();
+ }
+
+
+ void testListMessages_KMail() {
+
+ testListMessagesImpl(TEST_MAILDIR_KMAIL, TEST_MAILDIRFILES_KMAIL);
+ }
+
+ void testListMessages_Courier() {
+
+ testListMessagesImpl(TEST_MAILDIR_COURIER, TEST_MAILDIRFILES_COURIER);
+ }
+
+ void testListMessagesImpl(const vmime::string* const dirs, const vmime::string* const files) {
+
+ createMaildir(dirs, files);
+
+ vmime::shared_ptr <vmime::net::store> store = createAndConnectStore();
+ vmime::shared_ptr <vmime::net::folder> rootFolder = store->getRootFolder();
+
+ vmime::shared_ptr <vmime::net::folder> folder = store->getFolder(
+ fpath() / "Folder" / "SubFolder" / "SubSubFolder2"
+ );
+
+ vmime::size_t count, unseen;
+ folder->status(count, unseen);
+
+ VASSERT_EQ("Message count", 1, count);
+
+ folder->open(vmime::net::folder::MODE_READ_ONLY);
+
+ vmime::shared_ptr <vmime::net::message> msg = folder->getMessage(1);
+
+ folder->fetchMessage(msg, vmime::net::fetchAttributes::SIZE);
+
+ VASSERT_EQ("Message size", TEST_MESSAGE_1.length(), msg->getSize());
+
+ std::ostringstream oss;
+ vmime::utility::outputStreamAdapter os(oss);
+ msg->extract(os);
+
+ VASSERT_EQ("Message contents", TEST_MESSAGE_1, oss.str());
+
+ folder->close(false);
+
+ destroyMaildir();
+ }
+
+
+ void testRenameFolder_KMail() {
+
+ try {
+
+ testRenameFolderImpl(TEST_MAILDIR_KMAIL, TEST_MAILDIRFILES_KMAIL);
+
+ } catch (vmime::exception& e) {
+
+ std::cerr << e;
+ throw e;
+ }
+ }
+
+ void testRenameFolder_Courier()
+ {
+ try {
+
+ testRenameFolderImpl(TEST_MAILDIR_COURIER, TEST_MAILDIRFILES_COURIER);
+
+ } catch (vmime::exception& e) {
+
+ std::cerr << e;
+ throw e;
+ }
+ }
+
+ void testRenameFolderImpl(const vmime::string* const dirs, const vmime::string* const files) {
+
+ createMaildir(dirs, files);
+
+ vmime::shared_ptr <vmime::net::store> store = createAndConnectStore();
+ vmime::shared_ptr <vmime::net::folder> rootFolder = store->getRootFolder();
+
+ // Rename "Folder/SubFolder" to "Folder/foo"
+ vmime::shared_ptr <vmime::net::folder> folder =
+ store->getFolder(fpath() / "Folder" / "SubFolder");
+
+ folder->rename(fpath() / "Folder" / "foo");
+
+ // Ensure folder and its subfolders have been renamed
+ const std::vector <vmime::shared_ptr <vmime::net::folder> >
+ allFolders = rootFolder->getFolders(true);
+
+ VASSERT_EQ("1", 5, allFolders.size());
+ VASSERT("2", findFolder(allFolders, fpath() / "Folder") != NULL);
+ VASSERT("3", findFolder(allFolders, fpath() / "Folder" / "SubFolder") == NULL);
+ VASSERT("4", findFolder(allFolders, fpath() / "Folder" / "SubFolder" / "SubSubFolder1") == NULL);
+ VASSERT("5", findFolder(allFolders, fpath() / "Folder" / "SubFolder" / "SubSubFolder2") == NULL);
+ VASSERT("6", findFolder(allFolders, fpath() / "Folder2") != NULL);
+ VASSERT("7", findFolder(allFolders, fpath() / "Folder" / "foo") != NULL);
+ VASSERT("8", findFolder(allFolders, fpath() / "Folder" / "foo" / "SubSubFolder1") != NULL);
+ VASSERT("9", findFolder(allFolders, fpath() / "Folder" / "foo" / "SubSubFolder2") != NULL);
+
+ destroyMaildir();
+ }
+
+
+ void testDestroyFolder_KMail() {
+
+ testDestroyFolderImpl(TEST_MAILDIR_KMAIL, TEST_MAILDIRFILES_KMAIL);
+ }
+
+ void testDestroyFolder_Courier() {
+
+ testDestroyFolderImpl(TEST_MAILDIR_COURIER, TEST_MAILDIRFILES_COURIER);
+ }
+
+ void testDestroyFolderImpl(const vmime::string* const dirs, const vmime::string* const files) {
+
+ createMaildir(dirs, files);
+
+ vmime::shared_ptr <vmime::net::store> store = createAndConnectStore();
+ vmime::shared_ptr <vmime::net::folder> rootFolder = store->getRootFolder();
+
+ // Destroy "Folder/SubFolder" (total: 3 folders)
+ vmime::shared_ptr <vmime::net::folder> folder =
+ store->getFolder(fpath() / "Folder" / "SubFolder");
+
+ folder->destroy();
+
+ // Ensure folder and its subfolders have been deleted and other folders still exist
+ const std::vector <vmime::shared_ptr <vmime::net::folder> >
+ allFolders = rootFolder->getFolders(true);
+
+ VASSERT_EQ("1", 2, allFolders.size());
+ VASSERT("2", findFolder(allFolders, fpath() / "Folder") != NULL);
+ VASSERT("3", findFolder(allFolders, fpath() / "Folder" / "SubFolder") == NULL);
+ VASSERT("4", findFolder(allFolders, fpath() / "Folder" / "SubFolder" / "SubSubFolder1") == NULL);
+ VASSERT("5", findFolder(allFolders, fpath() / "Folder" / "SubFolder" / "SubSubFolder2") == NULL);
+ VASSERT("6", findFolder(allFolders, fpath() / "Folder2") != NULL);
+
+ destroyMaildir();
+ }
+
+
+ void testFolderExists_KMail() {
+
+ testFolderExistsImpl(TEST_MAILDIR_KMAIL, TEST_MAILDIRFILES_KMAIL);
+ }
+
+ void testFolderExists_Courier() {
+
+ testFolderExistsImpl(TEST_MAILDIR_COURIER, TEST_MAILDIRFILES_COURIER);
+ }
+
+ void testFolderExistsImpl(const vmime::string* const dirs, const vmime::string* const files) {
+
+ createMaildir(dirs, files);
+
+ vmime::shared_ptr <vmime::net::store> store = createAndConnectStore();
+ vmime::shared_ptr <vmime::net::folder> rootFolder = store->getRootFolder();
+
+ VASSERT("1", store->getFolder(fpath() / "Folder" / "SubFolder")->exists());
+ VASSERT("2", !store->getFolder(fpath() / "Folder" / "SubSubFolder1")->exists());
+ VASSERT("3", store->getFolder(fpath() / "Folder2")->exists());
+ VASSERT("4", store->getFolder(fpath() / "Folder" / "SubFolder" / "SubSubFolder2")->exists());
+
+ destroyMaildir();
+ }
+
+
+ void testCreateFolder_KMail() {
+
+ testCreateFolderImpl(TEST_MAILDIR_KMAIL, TEST_MAILDIRFILES_KMAIL);
+ }
+
+ void testCreateFolder_Courier() {
+
+ testCreateFolderImpl(TEST_MAILDIR_COURIER, TEST_MAILDIRFILES_COURIER);
+ }
+
+ void testCreateFolderImpl(const vmime::string* const dirs, const vmime::string* const files) {
+
+ createMaildir(dirs, files);
+
+ vmime::shared_ptr <vmime::net::store> store = createAndConnectStore();
+ vmime::shared_ptr <vmime::net::folder> rootFolder = store->getRootFolder();
+
+ VASSERT("Before", !store->getFolder(fpath() / "Folder" / "NewFolder")->exists());
+
+ vmime::net::folderAttributes attribs;
+ attribs.setType(vmime::net::folderAttributes::TYPE_CONTAINS_MESSAGES);
+
+ VASSERT_NO_THROW("Creation", store->getFolder(fpath() / "Folder" / "NewFolder")->create(attribs));
+
+ VASSERT("After", store->getFolder(fpath() / "Folder" / "NewFolder")->exists());
+
+ destroyMaildir();
+ }
+
+private:
+
+ vmime::utility::file::path m_tempPath;
+
+
+ vmime::shared_ptr <vmime::net::store> createAndConnectStore() {
+
+ vmime::shared_ptr <vmime::net::session> session = vmime::net::session::create();
+
+ vmime::shared_ptr <vmime::net::store> store =
+ session->getStore(getStoreURL());
+
+ store->connect();
+
+ return store;
+ }
+
+ const vmime::shared_ptr <vmime::net::folder> findFolder(
+ const std::vector <vmime::shared_ptr <vmime::net::folder> >& folders,
+ const vmime::net::folder::path& path
+ ) {
+
+ for (size_t i = 0, n = folders.size() ; i < n ; ++i) {
+
+ if (folders[i]->getFullPath() == path) {
+ return folders[i];
+ }
+ }
+
+ return vmime::null;
+ }
+
+ const vmime::utility::url getStoreURL() {
+
+ vmime::shared_ptr <vmime::utility::fileSystemFactory> fsf =
+ vmime::platform::getHandler()->getFileSystemFactory();
+
+ vmime::utility::url url(std::string("maildir://localhost")
+ + fsf->pathToString(m_tempPath));
+
+ return url;
+ }
+
+ void createMaildir(const vmime::string* const dirs, const vmime::string* const files) {
+
+ vmime::shared_ptr <vmime::utility::fileSystemFactory> fsf =
+ vmime::platform::getHandler()->getFileSystemFactory();
+
+ vmime::shared_ptr <vmime::utility::file> rootDir = fsf->create(m_tempPath);
+ rootDir->createDirectory(false);
+
+ for (vmime::string const* dir = dirs ; *dir != "*" ; ++dir) {
+
+ vmime::shared_ptr <vmime::utility::file> fdir = fsf->create(m_tempPath / fsf->stringToPath(*dir));
+ fdir->createDirectory(false);
+ }
+
+ for (vmime::string const* file = files ; *file != "*" ; file += 2) {
+
+ const vmime::string& contents = *(file + 1);
+
+ vmime::shared_ptr <vmime::utility::file> ffile = fsf->create(m_tempPath / fsf->stringToPath(*file));
+ ffile->createFile();
+
+ vmime::shared_ptr <vmime::utility::fileWriter> fileWriter = ffile->getFileWriter();
+ vmime::shared_ptr <vmime::utility::outputStream> os = fileWriter->getOutputStream();
+
+ os->write(contents.data(), contents.length());
+ os->flush();
+
+ fileWriter = vmime::null;
+ }
+
+ }
+
+ void destroyMaildir() {
+
+ vmime::shared_ptr <vmime::utility::fileSystemFactory> fsf =
+ vmime::platform::getHandler()->getFileSystemFactory();
+
+ recursiveDelete(fsf->create(m_tempPath));
+ }
+
+ void recursiveDelete(vmime::shared_ptr <vmime::utility::file> dir) {
+
+ if (!dir->exists() || !dir->isDirectory()) {
+ return;
+ }
+
+ vmime::shared_ptr <vmime::utility::fileIterator> files = dir->getFiles();
+
+ // First, delete files and subdirectories in this directory
+ while (files->hasMoreElements()) {
+
+ vmime::shared_ptr <vmime::utility::file> file = files->nextElement();
+
+ if (file->isDirectory()) {
+
+ recursiveDelete(file);
+
+ } else {
+
+ try {
+ file->remove();
+ } catch (vmime::exceptions::filesystem_exception&) {
+ // Ignore
+ }
+ }
+ }
+
+ // Then, delete this (empty) directory
+ try {
+ dir->remove();
+ } catch (vmime::exceptions::filesystem_exception&) {
+ // Ignore
+ }
+ }
+
+VMIME_TEST_SUITE_END
diff --git a/vmime-master/tests/net/maildir/maildirUtilsTest.cpp b/vmime-master/tests/net/maildir/maildirUtilsTest.cpp
new file mode 100644
index 0000000..9deeebf
--- /dev/null
+++ b/vmime-master/tests/net/maildir/maildirUtilsTest.cpp
@@ -0,0 +1,54 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "tests/testUtils.hpp"
+
+#include "vmime/net/maildir/maildirUtils.hpp"
+
+
+using namespace vmime::net::maildir;
+
+
+VMIME_TEST_SUITE_BEGIN(maildirUtilsTest)
+
+ VMIME_TEST_LIST_BEGIN
+ VMIME_TEST(testMessageSetToNumberList)
+ VMIME_TEST_LIST_END
+
+
+ void testMessageSetToNumberList() {
+
+ const std::vector <size_t> msgNums =
+ maildirUtils::messageSetToNumberList(
+ vmime::net::messageSet::byNumber(5, -1),
+ /* msgCount */ 8
+ );
+
+ VASSERT_EQ("Count", 4, msgNums.size());
+ VASSERT_EQ("1", 5, msgNums[0]);
+ VASSERT_EQ("2", 6, msgNums[1]);
+ VASSERT_EQ("3", 7, msgNums[2]);
+ VASSERT_EQ("4", 8, msgNums[3]);
+ }
+
+VMIME_TEST_SUITE_END
diff --git a/vmime-master/tests/net/messageSetTest.cpp b/vmime-master/tests/net/messageSetTest.cpp
new file mode 100644
index 0000000..dee5dc8
--- /dev/null
+++ b/vmime-master/tests/net/messageSetTest.cpp
@@ -0,0 +1,229 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "tests/testUtils.hpp"
+
+#include "vmime/net/messageSet.hpp"
+
+
+VMIME_TEST_SUITE_BEGIN(messageSetTest)
+
+ VMIME_TEST_LIST_BEGIN
+ VMIME_TEST(testNumberSet_Single)
+ VMIME_TEST(testNumberSet_Range)
+ VMIME_TEST(testNumberSet_InvalidRange)
+ VMIME_TEST(testNumberSet_InvalidFirst)
+ VMIME_TEST(testNumberSet_InfiniteRange)
+ VMIME_TEST(testNumberSet_Multiple)
+ VMIME_TEST(testUIDSet_Single)
+ VMIME_TEST(testUIDSet_Range)
+ VMIME_TEST(testUIDSet_InfiniteRange)
+ VMIME_TEST(testUIDSet_MultipleNumeric)
+ VMIME_TEST(testUIDSet_MultipleNonNumeric)
+ VMIME_TEST(testIsNumberSet)
+ VMIME_TEST(testIsUIDSet)
+ VMIME_TEST(testMixedRanges)
+ VMIME_TEST_LIST_END
+
+
+ class messageSetStringEnumerator : public vmime::net::messageSetEnumerator {
+
+ public:
+
+ messageSetStringEnumerator()
+ : m_first(true) {
+
+ }
+
+ void enumerateNumberMessageRange(const vmime::net::numberMessageRange& range) {
+
+ if (!m_first) {
+ m_oss << ",";
+ }
+
+ if (range.getFirst() == range.getLast()) {
+ m_oss << range.getFirst();
+ } else if (range.getLast() == size_t(-1)) {
+ m_oss << range.getFirst() << ":(LAST)";
+ } else {
+ m_oss << range.getFirst() << ":" << range.getLast();
+ }
+
+ m_first = false;
+ }
+
+ void enumerateUIDMessageRange(const vmime::net::UIDMessageRange& range) {
+
+ if (!m_first) {
+ m_oss << ",";
+ }
+
+ if (range.getFirst() == range.getLast()) {
+ m_oss << range.getFirst();
+ } else if (range.getLast() == size_t(-1)) {
+ m_oss << range.getFirst() << ":(LAST)";
+ } else {
+ m_oss << range.getFirst() << ":" << range.getLast();
+ }
+
+ m_first = false;
+ }
+
+ const std::string str() const {
+
+ return m_oss.str();
+ }
+
+ private:
+
+ std::ostringstream m_oss;
+ bool m_first;
+ };
+
+
+ const std::string enumerateAsString(const vmime::net::messageSet& set) {
+
+ messageSetStringEnumerator en;
+ set.enumerate(en);
+
+ return en.str();
+ }
+
+
+ void testNumberSet_Single() {
+
+ VASSERT_EQ("str", "42", enumerateAsString(vmime::net::messageSet::byNumber(42)));
+ }
+
+ void testNumberSet_Range() {
+
+ VASSERT_EQ("str", "42:100", enumerateAsString(vmime::net::messageSet::byNumber(42, 100)));
+ }
+
+ void testNumberSet_InvalidRange() {
+
+ VASSERT_THROW("first > last", vmime::net::messageSet::byNumber(100, 42), std::invalid_argument);
+ }
+
+ void testNumberSet_InvalidFirst() {
+
+ VASSERT_THROW("first == -1", vmime::net::messageSet::byNumber(-1, 42), std::invalid_argument);
+ }
+
+ void testNumberSet_InfiniteRange() {
+
+ VASSERT_EQ("str", "42:(LAST)", enumerateAsString(vmime::net::messageSet::byNumber(42, -1)));
+ }
+
+ void testNumberSet_Multiple() {
+
+ std::vector <vmime::size_t> numbers;
+ numbers.push_back(1); // test grouping 1:3
+ numbers.push_back(89); // test sorting
+ numbers.push_back(2);
+ numbers.push_back(3);
+ numbers.push_back(42);
+ numbers.push_back(53); // test grouping 53:57
+ numbers.push_back(54);
+ numbers.push_back(55);
+ numbers.push_back(56);
+ numbers.push_back(56); // test duplicates
+ numbers.push_back(57);
+ numbers.push_back(99);
+
+ VASSERT_EQ("str", "1:3,42,53:57,89,99", enumerateAsString(vmime::net::messageSet::byNumber(numbers)));
+ }
+
+
+ void testUIDSet_Single() {
+
+ VASSERT_EQ("str", "abcdef", enumerateAsString(vmime::net::messageSet::byUID("abcdef")));
+ }
+
+ void testUIDSet_Range() {
+
+ VASSERT_EQ("str", "abc:def", enumerateAsString(vmime::net::messageSet::byUID("abc:def")));
+ }
+
+ void testUIDSet_InfiniteRange() {
+
+ VASSERT_EQ("str", "abc:*", enumerateAsString(vmime::net::messageSet::byUID("abc", "*")));
+ }
+
+ void testUIDSet_MultipleNumeric() {
+
+ std::vector <vmime::net::message::uid> uids;
+ uids.push_back("1"); // test grouping 1:3
+ uids.push_back("89"); // test sorting
+ uids.push_back("2");
+ uids.push_back("3");
+ uids.push_back("42");
+ uids.push_back("53"); // test grouping 53:57
+ uids.push_back("54");
+ uids.push_back("55");
+ uids.push_back("56");
+ uids.push_back("56"); // test duplicates
+ uids.push_back("57");
+ uids.push_back("99");
+
+ VASSERT_EQ("str", "1:3,42,53:57,89,99", enumerateAsString(vmime::net::messageSet::byUID(uids)));
+ }
+
+ void testUIDSet_MultipleNonNumeric() {
+
+ std::vector <vmime::net::message::uid> uids;
+ uids.push_back("12");
+ uids.push_back("34");
+ uids.push_back("ab56");
+ uids.push_back("78cd");
+
+ VASSERT_EQ("str", "12,34,ab56,78cd", enumerateAsString(vmime::net::messageSet::byUID(uids)));
+ }
+
+ void testIsNumberSet() {
+
+ VASSERT_TRUE("number1", vmime::net::messageSet::byNumber(42).isNumberSet());
+ VASSERT_FALSE("uid1", vmime::net::messageSet::byUID("42").isNumberSet());
+
+ VASSERT_TRUE("number2", vmime::net::messageSet::byNumber(42, -1).isNumberSet());
+ VASSERT_FALSE("uid2", vmime::net::messageSet::byUID("42", "*").isNumberSet());
+ }
+
+ void testIsUIDSet() {
+
+ VASSERT_FALSE("number1", vmime::net::messageSet::byNumber(42).isUIDSet());
+ VASSERT_TRUE("uid1", vmime::net::messageSet::byUID("42").isUIDSet());
+
+ VASSERT_FALSE("number2", vmime::net::messageSet::byNumber(42, -1).isUIDSet());
+ VASSERT_TRUE("uid2", vmime::net::messageSet::byUID("42", "*").isUIDSet());
+ }
+
+ void testMixedRanges() {
+
+ vmime::net::messageSet set = vmime::net::messageSet::byNumber(1, 5);
+ set.addRange(vmime::net::numberMessageRange(6, 8));
+
+ VASSERT_THROW("mixed ranges", set.addRange(vmime::net::UIDMessageRange("123")), std::invalid_argument);
+ }
+
+VMIME_TEST_SUITE_END
diff --git a/vmime-master/tests/net/pop3/POP3CommandTest.cpp b/vmime-master/tests/net/pop3/POP3CommandTest.cpp
new file mode 100644
index 0000000..3ed579e
--- /dev/null
+++ b/vmime-master/tests/net/pop3/POP3CommandTest.cpp
@@ -0,0 +1,241 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "tests/testUtils.hpp"
+
+#include "tests/net/pop3/POP3TestUtils.hpp"
+
+#include "vmime/net/pop3/POP3Command.hpp"
+
+
+using namespace vmime::net::pop3;
+
+
+VMIME_TEST_SUITE_BEGIN(POP3CommandTest)
+
+ VMIME_TEST_LIST_BEGIN
+ VMIME_TEST(testCreateCommand)
+ VMIME_TEST(testCreateCommandParams)
+ VMIME_TEST(testCAPA)
+ VMIME_TEST(testNOOP)
+ VMIME_TEST(testAUTH)
+ VMIME_TEST(testAUTH_InitialResponse)
+ VMIME_TEST(testSTLS)
+ VMIME_TEST(testAPOP)
+ VMIME_TEST(testUSER)
+ VMIME_TEST(testPASS)
+ VMIME_TEST(testSTAT)
+ VMIME_TEST(testLIST)
+ VMIME_TEST(testLISTMessage)
+ VMIME_TEST(testUIDL)
+ VMIME_TEST(testUIDLMessage)
+ VMIME_TEST(testDELE)
+ VMIME_TEST(testRETR)
+ VMIME_TEST(testTOP)
+ VMIME_TEST(testRSET)
+ VMIME_TEST(testQUIT)
+ VMIME_TEST(testWriteToSocket)
+ VMIME_TEST_LIST_END
+
+
+ void testCreateCommand() {
+
+ vmime::shared_ptr <POP3Command> cmd = POP3Command::createCommand("MY_COMMAND");
+
+ VASSERT_NOT_NULL("Not null", cmd);
+ VASSERT_EQ("Text", "MY_COMMAND", cmd->getText());
+ }
+
+ void testCreateCommandParams() {
+
+ vmime::shared_ptr <POP3Command> cmd = POP3Command::createCommand("MY_COMMAND param1 param2");
+
+ VASSERT_NOT_NULL("Not null", cmd);
+ VASSERT_EQ("Text", "MY_COMMAND param1 param2", cmd->getText());
+ }
+
+ void testCAPA() {
+
+ vmime::shared_ptr <POP3Command> cmd = POP3Command::CAPA();
+
+ VASSERT_NOT_NULL("Not null", cmd);
+ VASSERT_EQ("Text", "CAPA", cmd->getText());
+ }
+
+ void testNOOP() {
+
+ vmime::shared_ptr <POP3Command> cmd = POP3Command::NOOP();
+
+ VASSERT_NOT_NULL("Not null", cmd);
+ VASSERT_EQ("Text", "NOOP", cmd->getText());
+ }
+
+ void testAUTH() {
+
+ vmime::shared_ptr <POP3Command> cmd = POP3Command::AUTH("saslmechanism");
+
+ VASSERT_NOT_NULL("Not null", cmd);
+ VASSERT_EQ("Text", "AUTH saslmechanism", cmd->getText());
+ }
+
+ void testAUTH_InitialResponse() {
+
+ vmime::shared_ptr <POP3Command> cmd = POP3Command::AUTH("saslmechanism", "initial-response");
+
+ VASSERT_NOT_NULL("Not null", cmd);
+ VASSERT_EQ("Text", "AUTH saslmechanism initial-response", cmd->getText());
+ }
+
+ void testSTLS() {
+
+ vmime::shared_ptr <POP3Command> cmd = POP3Command::STLS();
+
+ VASSERT_NOT_NULL("Not null", cmd);
+ VASSERT_EQ("Text", "STLS", cmd->getText());
+ }
+
+ void testAPOP() {
+
+ vmime::shared_ptr <POP3Command> cmd = POP3Command::APOP("user", "digest");
+
+ VASSERT_NOT_NULL("Not null", cmd);
+ VASSERT_EQ("Text", "APOP user digest", cmd->getText());
+ }
+
+ void testUSER() {
+
+ vmime::shared_ptr <POP3Command> cmd = POP3Command::USER("user");
+
+ VASSERT_NOT_NULL("Not null", cmd);
+ VASSERT_EQ("Text", "USER user", cmd->getText());
+ }
+
+ void testPASS() {
+
+ vmime::shared_ptr <POP3Command> cmd = POP3Command::PASS("pass");
+
+ VASSERT_NOT_NULL("Not null", cmd);
+ VASSERT_EQ("Text", "PASS pass", cmd->getText());
+ }
+
+ void testSTAT() {
+
+ vmime::shared_ptr <POP3Command> cmd = POP3Command::STAT();
+
+ VASSERT_NOT_NULL("Not null", cmd);
+ VASSERT_EQ("Text", "STAT", cmd->getText());
+ }
+
+ void testLIST() {
+
+ vmime::shared_ptr <POP3Command> cmd = POP3Command::LIST();
+
+ VASSERT_NOT_NULL("Not null", cmd);
+ VASSERT_EQ("Text", "LIST", cmd->getText());
+ }
+
+ void testLISTMessage() {
+
+ vmime::shared_ptr <POP3Command> cmd = POP3Command::LIST(42);
+
+ VASSERT_NOT_NULL("Not null", cmd);
+ VASSERT_EQ("Text", "LIST 42", cmd->getText());
+ }
+
+ void testUIDL() {
+
+ vmime::shared_ptr <POP3Command> cmd = POP3Command::UIDL();
+
+ VASSERT_NOT_NULL("Not null", cmd);
+ VASSERT_EQ("Text", "UIDL", cmd->getText());
+ }
+
+ void testUIDLMessage() {
+
+ vmime::shared_ptr <POP3Command> cmd = POP3Command::UIDL(42);
+
+ VASSERT_NOT_NULL("Not null", cmd);
+ VASSERT_EQ("Text", "UIDL 42", cmd->getText());
+ }
+
+ void testDELE() {
+
+ vmime::shared_ptr <POP3Command> cmd = POP3Command::DELE(42);
+
+ VASSERT_NOT_NULL("Not null", cmd);
+ VASSERT_EQ("Text", "DELE 42", cmd->getText());
+ }
+
+ void testRETR() {
+
+ vmime::shared_ptr <POP3Command> cmd = POP3Command::RETR(42);
+
+ VASSERT_NOT_NULL("Not null", cmd);
+ VASSERT_EQ("Text", "RETR 42", cmd->getText());
+ }
+
+ void testTOP() {
+
+ vmime::shared_ptr <POP3Command> cmd = POP3Command::TOP(42, 567);
+
+ VASSERT_NOT_NULL("Not null", cmd);
+ VASSERT_EQ("Text", "TOP 42 567", cmd->getText());
+ }
+
+ void testRSET() {
+
+ vmime::shared_ptr <POP3Command> cmd = POP3Command::RSET();
+
+ VASSERT_NOT_NULL("Not null", cmd);
+ VASSERT_EQ("Text", "RSET", cmd->getText());
+ }
+
+ void testQUIT() {
+
+ vmime::shared_ptr <POP3Command> cmd = POP3Command::QUIT();
+
+ VASSERT_NOT_NULL("Not null", cmd);
+ VASSERT_EQ("Text", "QUIT", cmd->getText());
+ }
+
+ void testWriteToSocket() {
+
+ vmime::shared_ptr <POP3Command> cmd = POP3Command::createCommand("MY_COMMAND param1 param2");
+
+ vmime::shared_ptr <testSocket> sok = vmime::make_shared <testSocket>();
+
+ vmime::shared_ptr <POP3ConnectionTest> conn =
+ vmime::make_shared <POP3ConnectionTest>(
+ vmime::dynamicCast <vmime::net::socket>(sok),
+ vmime::shared_ptr <vmime::net::timeoutHandler>()
+ );
+
+ cmd->send(conn);
+
+ vmime::string response;
+ sok->localReceive(response);
+
+ VASSERT_EQ("Sent buffer", "MY_COMMAND param1 param2\r\n", response);
+ }
+
+VMIME_TEST_SUITE_END
diff --git a/vmime-master/tests/net/pop3/POP3ResponseTest.cpp b/vmime-master/tests/net/pop3/POP3ResponseTest.cpp
new file mode 100644
index 0000000..8fecb74
--- /dev/null
+++ b/vmime-master/tests/net/pop3/POP3ResponseTest.cpp
@@ -0,0 +1,244 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "tests/testUtils.hpp"
+
+#include "tests/net/pop3/POP3TestUtils.hpp"
+
+#include "vmime/net/pop3/POP3Response.hpp"
+
+
+using namespace vmime::net::pop3;
+
+
+VMIME_TEST_SUITE_BEGIN(POP3ResponseTest)
+
+ VMIME_TEST_LIST_BEGIN
+ VMIME_TEST(testSingleLineResponseOK)
+ VMIME_TEST(testSingleLineResponseERR)
+ VMIME_TEST(testSingleLineResponseReady)
+ VMIME_TEST(testSingleLineResponseInvalid)
+ VMIME_TEST(testSingleLineResponseLF)
+ VMIME_TEST(testMultiLineResponse)
+ VMIME_TEST(testMultiLineResponseLF)
+ VMIME_TEST(testLargeResponse)
+ VMIME_TEST_LIST_END
+
+
+ void testSingleLineResponseOK() {
+
+ vmime::shared_ptr <testSocket> socket = vmime::make_shared <testSocket>();
+ vmime::shared_ptr <vmime::net::timeoutHandler> toh = vmime::make_shared <testTimeoutHandler>();
+
+ vmime::shared_ptr <POP3ConnectionTest> conn =
+ vmime::make_shared <POP3ConnectionTest>(
+ vmime::dynamicCast <vmime::net::socket>(socket), toh
+ );
+
+ socket->localSend("+OK Response Text\r\n");
+
+ vmime::shared_ptr <POP3Response> resp =
+ POP3Response::readResponse(conn);
+
+ VASSERT_EQ("Code", POP3Response::CODE_OK, resp->getCode());
+ VASSERT_TRUE("Success", resp->isSuccess());
+ VASSERT_EQ("Lines", 0, resp->getLineCount());
+ VASSERT_EQ("Text", "Response Text", resp->getText());
+ VASSERT_EQ("First Line", "+OK Response Text", resp->getFirstLine());
+ }
+
+ void testSingleLineResponseERR() {
+
+ vmime::shared_ptr <testSocket> socket = vmime::make_shared <testSocket>();
+ vmime::shared_ptr <vmime::net::timeoutHandler> toh = vmime::make_shared <testTimeoutHandler>();
+
+ vmime::shared_ptr <POP3ConnectionTest> conn =
+ vmime::make_shared <POP3ConnectionTest>(
+ vmime::dynamicCast <vmime::net::socket>(socket), toh
+ );
+
+ socket->localSend("-ERR Response Text\r\n");
+
+ vmime::shared_ptr <POP3Response> resp =
+ POP3Response::readResponse(conn);
+
+ VASSERT_EQ("Code", POP3Response::CODE_ERR, resp->getCode());
+ VASSERT_FALSE("Success", resp->isSuccess());
+ VASSERT_EQ("Lines", 0, resp->getLineCount());
+ VASSERT_EQ("Text", "Response Text", resp->getText());
+ VASSERT_EQ("First Line", "-ERR Response Text", resp->getFirstLine());
+ }
+
+ void testSingleLineResponseReady() {
+
+ vmime::shared_ptr <testSocket> socket = vmime::make_shared <testSocket>();
+ vmime::shared_ptr <vmime::net::timeoutHandler> toh = vmime::make_shared <testTimeoutHandler>();
+
+ vmime::shared_ptr <POP3ConnectionTest> conn =
+ vmime::make_shared <POP3ConnectionTest>(
+ vmime::dynamicCast <vmime::net::socket>(socket), toh
+ );
+
+ socket->localSend("+ challenge_string\r\n");
+
+ vmime::shared_ptr <POP3Response> resp =
+ POP3Response::readResponse(conn);
+
+ VASSERT_EQ("Code", POP3Response::CODE_READY, resp->getCode());
+ VASSERT_FALSE("Success", resp->isSuccess());
+ VASSERT_EQ("Lines", 0, resp->getLineCount());
+ VASSERT_EQ("Text", "challenge_string", resp->getText());
+ VASSERT_EQ("First Line", "+ challenge_string", resp->getFirstLine());
+ }
+
+ void testSingleLineResponseInvalid() {
+
+ vmime::shared_ptr <testSocket> socket = vmime::make_shared <testSocket>();
+ vmime::shared_ptr <vmime::net::timeoutHandler> toh = vmime::make_shared <testTimeoutHandler>();
+
+ vmime::shared_ptr <POP3ConnectionTest> conn = vmime::make_shared <POP3ConnectionTest>
+ (vmime::dynamicCast <vmime::net::socket>(socket), toh);
+
+ socket->localSend("Invalid Response Text\r\n");
+
+ vmime::shared_ptr <POP3Response> resp =
+ POP3Response::readResponse(conn);
+
+ VASSERT_EQ("Code", POP3Response::CODE_ERR, resp->getCode());
+ VASSERT_FALSE("Success", resp->isSuccess());
+ VASSERT_EQ("Lines", 0, resp->getLineCount());
+ VASSERT_EQ("Text", "Response Text", resp->getText());
+ VASSERT_EQ("First Line", "Invalid Response Text", resp->getFirstLine());
+ }
+
+ void testSingleLineResponseLF() {
+
+ vmime::shared_ptr <testSocket> socket = vmime::make_shared <testSocket>();
+ vmime::shared_ptr <vmime::net::timeoutHandler> toh = vmime::make_shared <testTimeoutHandler>();
+
+ vmime::shared_ptr <POP3ConnectionTest> conn =
+ vmime::make_shared <POP3ConnectionTest>(
+ vmime::dynamicCast <vmime::net::socket>(socket), toh
+ );
+
+ socket->localSend("+OK Response terminated by LF\n");
+
+ vmime::shared_ptr <POP3Response> resp =
+ POP3Response::readResponse(conn);
+
+ VASSERT_EQ("Code", POP3Response::CODE_OK, resp->getCode());
+ VASSERT_TRUE("Success", resp->isSuccess());
+ VASSERT_EQ("Lines", 0, resp->getLineCount());
+ VASSERT_EQ("Text", "Response terminated by LF", resp->getText());
+ VASSERT_EQ("First Line", "+OK Response terminated by LF", resp->getFirstLine());
+ }
+
+ void testMultiLineResponse() {
+
+ vmime::shared_ptr <testSocket> socket = vmime::make_shared <testSocket>();
+ vmime::shared_ptr <vmime::net::timeoutHandler> toh = vmime::make_shared <testTimeoutHandler>();
+
+ vmime::shared_ptr <POP3ConnectionTest> conn =
+ vmime::make_shared <POP3ConnectionTest>(
+ vmime::dynamicCast <vmime::net::socket>(socket), toh
+ );
+
+ socket->localSend("+OK Response Text\r\n");
+ socket->localSend("Line 1\r\n");
+ socket->localSend("Line 2\r\n");
+ socket->localSend(".\r\n");
+
+ vmime::shared_ptr <POP3Response> resp =
+ POP3Response::readMultilineResponse(conn);
+
+ VASSERT_EQ("Code", POP3Response::CODE_OK, resp->getCode());
+ VASSERT_TRUE("Success", resp->isSuccess());
+ VASSERT_EQ("Lines", 2, resp->getLineCount());
+ VASSERT_EQ("Text", "Response Text", resp->getText());
+ VASSERT_EQ("First Line", "+OK Response Text", resp->getFirstLine());
+ VASSERT_EQ("Line 1", "Line 1", resp->getLineAt(0));
+ VASSERT_EQ("Line 2", "Line 2", resp->getLineAt(1));
+ }
+
+ void testMultiLineResponseLF() {
+
+ vmime::shared_ptr <testSocket> socket = vmime::make_shared <testSocket>();
+ vmime::shared_ptr <vmime::net::timeoutHandler> toh = vmime::make_shared <testTimeoutHandler>();
+
+ vmime::shared_ptr <POP3ConnectionTest> conn =
+ vmime::make_shared <POP3ConnectionTest>(
+ vmime::dynamicCast <vmime::net::socket>(socket), toh
+ );
+
+ socket->localSend("+OK Response Text\n");
+ socket->localSend("Line 1\n");
+ socket->localSend("Line 2\n");
+ socket->localSend(".\n");
+
+ vmime::shared_ptr <POP3Response> resp =
+ POP3Response::readMultilineResponse(conn);
+
+ VASSERT_EQ("Code", POP3Response::CODE_OK, resp->getCode());
+ VASSERT_TRUE("Success", resp->isSuccess());
+ VASSERT_EQ("Lines", 2, resp->getLineCount());
+ VASSERT_EQ("Text", "Response Text", resp->getText());
+ VASSERT_EQ("First Line", "+OK Response Text", resp->getFirstLine());
+ VASSERT_EQ("Line 1", "Line 1", resp->getLineAt(0));
+ VASSERT_EQ("Line 2", "Line 2", resp->getLineAt(1));
+ }
+
+ void testLargeResponse() {
+
+ std::ostringstream data;
+
+ for (unsigned int i = 0 ; i < 5000 ; ++i) {
+ data << "VMIME.VMIME\nVMIME\r\nVMIME_VMIME";
+ }
+
+ vmime::shared_ptr <testSocket> socket = vmime::make_shared <testSocket>();
+ vmime::shared_ptr <vmime::net::timeoutHandler> toh = vmime::make_shared <testTimeoutHandler>();
+
+ vmime::shared_ptr <POP3ConnectionTest> conn =
+ vmime::make_shared <POP3ConnectionTest>(
+ vmime::dynamicCast <vmime::net::socket>(socket), toh
+ );
+
+ socket->localSend("+OK Large Response Follows\n");
+ socket->localSend(data.str());
+ socket->localSend("\r\n.\r\n");
+
+ vmime::string receivedData;
+ vmime::utility::outputStreamStringAdapter receivedDataStream(receivedData);
+
+ vmime::shared_ptr <POP3Response> resp =
+ POP3Response::readLargeResponse(conn, receivedDataStream, NULL, 0);
+
+ VASSERT_EQ("Code", POP3Response::CODE_OK, resp->getCode());
+ VASSERT_TRUE("Success", resp->isSuccess());
+ VASSERT_EQ("Lines", 0, resp->getLineCount());
+ VASSERT_EQ("Text", "Large Response Follows", resp->getText());
+ VASSERT_EQ("Data Length", data.str().length(), receivedData.length());
+ VASSERT_EQ("Data Bytes", data.str(), receivedData);
+ }
+
+VMIME_TEST_SUITE_END
diff --git a/vmime-master/tests/net/pop3/POP3StoreTest.cpp b/vmime-master/tests/net/pop3/POP3StoreTest.cpp
new file mode 100644
index 0000000..5d9e3c2
--- /dev/null
+++ b/vmime-master/tests/net/pop3/POP3StoreTest.cpp
@@ -0,0 +1,67 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "tests/testUtils.hpp"
+
+#include "tests/net/pop3/POP3TestUtils.hpp"
+
+#include "vmime/net/pop3/POP3Store.hpp"
+#include "vmime/net/pop3/POP3SStore.hpp"
+
+
+VMIME_TEST_SUITE_BEGIN(POP3StoreTest)
+
+ VMIME_TEST_LIST_BEGIN
+ VMIME_TEST(testCreateFromURL)
+ VMIME_TEST(testConnectToInvalidServer)
+ VMIME_TEST_LIST_END
+
+
+ void testCreateFromURL() {
+
+ vmime::shared_ptr <vmime::net::session> sess = vmime::net::session::create();
+
+ // POP3
+ vmime::utility::url url("pop3://pop3.vmime.org");
+ vmime::shared_ptr <vmime::net::store> store = sess->getStore(url);
+
+ VASSERT_TRUE("pop3", typeid(*store) == typeid(vmime::net::pop3::POP3Store));
+
+ // POP3S
+ vmime::utility::url url2("pop3s://pop3s.vmime.org");
+ vmime::shared_ptr <vmime::net::store> store2 = sess->getStore(url2);
+
+ VASSERT_TRUE("pop3s", typeid(*store2) == typeid(vmime::net::pop3::POP3SStore));
+ }
+
+ void testConnectToInvalidServer() {
+
+ vmime::shared_ptr <vmime::net::session> sess = vmime::net::session::create();
+
+ vmime::utility::url url("pop3://invalid-pop3-server");
+ vmime::shared_ptr <vmime::net::store> store = sess->getStore(url);
+
+ VASSERT_THROW("connect", store->connect(), vmime::exceptions::connection_error);
+ }
+
+VMIME_TEST_SUITE_END
diff --git a/vmime-master/tests/net/pop3/POP3TestUtils.hpp b/vmime-master/tests/net/pop3/POP3TestUtils.hpp
new file mode 100644
index 0000000..24efb8b
--- /dev/null
+++ b/vmime-master/tests/net/pop3/POP3TestUtils.hpp
@@ -0,0 +1,69 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/net/pop3/POP3Connection.hpp"
+#include "vmime/net/pop3/POP3Store.hpp"
+
+
+class POP3TestStore : public vmime::net::pop3::POP3Store {
+
+public:
+
+ POP3TestStore()
+ : POP3Store(vmime::net::session::create(),
+ vmime::shared_ptr <vmime::security::authenticator>()) {
+
+ }
+};
+
+
+class POP3ConnectionTest : public vmime::net::pop3::POP3Connection {
+
+public:
+
+ POP3ConnectionTest(
+ vmime::shared_ptr <vmime::net::socket> socket,
+ vmime::shared_ptr <vmime::net::timeoutHandler> timeoutHandler
+ )
+ : POP3Connection(vmime::make_shared <POP3TestStore>(),
+ vmime::shared_ptr <vmime::security::authenticator>()),
+ m_socket(socket),
+ m_timeoutHandler(timeoutHandler) {
+
+ }
+
+ vmime::shared_ptr <vmime::net::socket> getSocket() {
+
+ return m_socket;
+ }
+
+ vmime::shared_ptr <vmime::net::timeoutHandler> getTimeoutHandler() {
+
+ return m_timeoutHandler;
+ }
+
+private:
+
+ vmime::shared_ptr <vmime::net::socket> m_socket;
+ vmime::shared_ptr <vmime::net::timeoutHandler> m_timeoutHandler;
+};
diff --git a/vmime-master/tests/net/pop3/POP3UtilsTest.cpp b/vmime-master/tests/net/pop3/POP3UtilsTest.cpp
new file mode 100644
index 0000000..1cded39
--- /dev/null
+++ b/vmime-master/tests/net/pop3/POP3UtilsTest.cpp
@@ -0,0 +1,88 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "tests/testUtils.hpp"
+
+#include "tests/net/pop3/POP3TestUtils.hpp"
+
+#include "vmime/net/pop3/POP3Utils.hpp"
+#include "vmime/net/pop3/POP3Response.hpp"
+
+
+using namespace vmime::net::pop3;
+
+
+VMIME_TEST_SUITE_BEGIN(POP3UtilsTest)
+
+ VMIME_TEST_LIST_BEGIN
+ VMIME_TEST(testParseMultiListOrUidlResponse)
+ VMIME_TEST(testMessageSetToNumberList)
+ VMIME_TEST_LIST_END
+
+
+ void testParseMultiListOrUidlResponse() {
+
+ vmime::shared_ptr <testSocket> socket = vmime::make_shared <testSocket>();
+ vmime::shared_ptr <vmime::net::timeoutHandler> toh = vmime::make_shared <testTimeoutHandler>();
+
+ vmime::shared_ptr <POP3ConnectionTest> conn =
+ vmime::make_shared <POP3ConnectionTest>(
+ vmime::dynamicCast <vmime::net::socket>(socket), toh
+ );
+
+ socket->localSend("+OK Response Text\r\n");
+ socket->localSend("1 abcdef\r\n");
+ socket->localSend("23 ghijkl\r\n");
+ socket->localSend("4\tmnopqr\r\n");
+ socket->localSend("567xx\tstuvwx\r\n");
+ socket->localSend("8 yz \r\n");
+ socket->localSend(".\r\n");
+
+ vmime::shared_ptr <POP3Response> resp =
+ POP3Response::readMultilineResponse(conn);
+
+ std::map <vmime::size_t, vmime::string> result;
+ POP3Utils::parseMultiListOrUidlResponse(resp, result);
+
+ VASSERT_EQ("Count", 5, result.size());
+ VASSERT_EQ("1", "abcdef", result[1]);
+ VASSERT_EQ("2 (multiple spaces)", "ghijkl", result[23]);
+ VASSERT_EQ("3 (with tab)", "mnopqr", result[4]);
+ VASSERT_EQ("4 (with invalid digit)", "stuvwx", result[567]);
+ VASSERT_EQ("5 (with extra space)", "yz", result[8]);
+ }
+
+ void testMessageSetToNumberList() {
+
+ const std::vector <size_t> msgNums = POP3Utils::messageSetToNumberList(
+ vmime::net::messageSet::byNumber(5, -1), /* msgCount */ 8
+ );
+
+ VASSERT_EQ("Count", 4, msgNums.size());
+ VASSERT_EQ("1", 5, msgNums[0]);
+ VASSERT_EQ("2", 6, msgNums[1]);
+ VASSERT_EQ("3", 7, msgNums[2]);
+ VASSERT_EQ("4", 8, msgNums[3]);
+ }
+
+VMIME_TEST_SUITE_END
diff --git a/vmime-master/tests/net/smtp/SMTPCommandSetTest.cpp b/vmime-master/tests/net/smtp/SMTPCommandSetTest.cpp
new file mode 100644
index 0000000..7ea3578
--- /dev/null
+++ b/vmime-master/tests/net/smtp/SMTPCommandSetTest.cpp
@@ -0,0 +1,181 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "tests/testUtils.hpp"
+
+#include "vmime/net/smtp/SMTPCommandSet.hpp"
+#include "vmime/net/smtp/SMTPCommand.hpp"
+
+
+using namespace vmime::net::smtp;
+
+
+VMIME_TEST_SUITE_BEGIN(SMTPCommandSetTest)
+
+ VMIME_TEST_LIST_BEGIN
+ VMIME_TEST(testCreate)
+ VMIME_TEST(testCreatePipeline)
+ VMIME_TEST(testAddCommand)
+ VMIME_TEST(testAddCommandPipeline)
+ VMIME_TEST(testWriteToSocket)
+ VMIME_TEST(testWriteToSocketPipeline)
+ VMIME_TEST(testGetLastCommandSent)
+ VMIME_TEST(testGetLastCommandSentPipeline)
+ VMIME_TEST_LIST_END
+
+
+ void testCreate() {
+
+ vmime::shared_ptr <SMTPCommandSet> cset = SMTPCommandSet::create(/* pipelining */ false);
+
+ VASSERT_NOT_NULL("Not null", cset);
+ VASSERT_FALSE("Finished", cset->isFinished());
+ }
+
+ void testCreatePipeline() {
+
+ vmime::shared_ptr <SMTPCommandSet> cset = SMTPCommandSet::create(/* pipelining */ true);
+
+ VASSERT_NOT_NULL("Not null", cset);
+ VASSERT_FALSE("Finished", cset->isFinished());
+ }
+
+ void testAddCommand() {
+
+ vmime::shared_ptr <SMTPCommandSet> cset = SMTPCommandSet::create(/* pipelining */ false);
+
+ VASSERT_NO_THROW("No throw 1", cset->addCommand(SMTPCommand::createCommand("MY_COMMAND1")));
+ VASSERT_EQ("Text", "MY_COMMAND1\r\n", cset->getText());
+ VASSERT_NO_THROW("No throw 2", cset->addCommand(SMTPCommand::createCommand("MY_COMMAND2")));
+ VASSERT_EQ("Text", "MY_COMMAND1\r\nMY_COMMAND2\r\n", cset->getText());
+
+ vmime::shared_ptr <vmime::net::tracer> tracer;
+ vmime::shared_ptr <testSocket> sok = vmime::make_shared <testSocket>();
+
+ cset->writeToSocket(sok, tracer);
+ VASSERT_FALSE("Finished", cset->isFinished());
+
+ // Can't add commands when writing to socket has started
+ VASSERT_THROW("Throw", cset->addCommand(SMTPCommand::createCommand("MY_COMMAND3")), std::runtime_error);
+
+ cset->writeToSocket(sok, tracer);
+ VASSERT_TRUE("Finished", cset->isFinished());
+ }
+
+ void testAddCommandPipeline() {
+
+ vmime::shared_ptr <SMTPCommandSet> cset = SMTPCommandSet::create(/* pipelining */ true);
+
+ VASSERT_NO_THROW("No throw 1", cset->addCommand(SMTPCommand::createCommand("MY_COMMAND1")));
+ VASSERT_EQ("Text", "MY_COMMAND1\r\n", cset->getText());
+ VASSERT_NO_THROW("No throw 2", cset->addCommand(SMTPCommand::createCommand("MY_COMMAND2")));
+ VASSERT_EQ("Text", "MY_COMMAND1\r\nMY_COMMAND2\r\n", cset->getText());
+
+ vmime::shared_ptr <vmime::net::tracer> tracer;
+ vmime::shared_ptr <testSocket> sok = vmime::make_shared <testSocket>();
+ vmime::string response;
+
+ cset->writeToSocket(sok, tracer);
+ VASSERT_TRUE("Finished", cset->isFinished());
+
+ sok->localReceive(response);
+ VASSERT_EQ("Receive cmds", "MY_COMMAND1\r\nMY_COMMAND2\r\n", response);
+
+ // Can't add commands when writing to socket has started
+ VASSERT_THROW("Throw", cset->addCommand(SMTPCommand::createCommand("MY_COMMAND3")), std::runtime_error);
+ }
+
+ void testWriteToSocket() {
+
+ vmime::shared_ptr <SMTPCommandSet> cset = SMTPCommandSet::create(/* pipelining */ false);
+
+ cset->addCommand(SMTPCommand::createCommand("MY_COMMAND1"));
+ cset->addCommand(SMTPCommand::createCommand("MY_COMMAND2"));
+
+ vmime::shared_ptr <vmime::net::tracer> tracer;
+ vmime::shared_ptr <testSocket> sok = vmime::make_shared <testSocket>();
+ vmime::string response;
+
+ cset->writeToSocket(sok, tracer);
+
+ sok->localReceive(response);
+ VASSERT_EQ("Receive cmd 1", "MY_COMMAND1\r\n", response);
+
+ cset->writeToSocket(sok, tracer);
+
+ sok->localReceive(response);
+ VASSERT_EQ("Receive cmd 2", "MY_COMMAND2\r\n", response);
+ }
+
+ void testWriteToSocketPipeline() {
+
+ vmime::shared_ptr <SMTPCommandSet> cset = SMTPCommandSet::create(/* pipelining */ true);
+
+ cset->addCommand(SMTPCommand::createCommand("MY_COMMAND1"));
+ cset->addCommand(SMTPCommand::createCommand("MY_COMMAND2"));
+
+ vmime::shared_ptr <vmime::net::tracer> tracer;
+ vmime::shared_ptr <testSocket> sok = vmime::make_shared <testSocket>();
+ vmime::string response;
+
+ cset->writeToSocket(sok, tracer);
+
+ sok->localReceive(response);
+ VASSERT_EQ("Receive cmds", "MY_COMMAND1\r\nMY_COMMAND2\r\n", response);
+ }
+
+ void testGetLastCommandSent() {
+
+ vmime::shared_ptr <SMTPCommandSet> cset = SMTPCommandSet::create(/* pipelining */ false);
+
+ cset->addCommand(SMTPCommand::createCommand("MY_COMMAND1"));
+ cset->addCommand(SMTPCommand::createCommand("MY_COMMAND2"));
+
+ vmime::shared_ptr <vmime::net::tracer> tracer;
+ vmime::shared_ptr <testSocket> sok = vmime::make_shared <testSocket>();
+
+ cset->writeToSocket(sok, tracer);
+ VASSERT_EQ("Cmd 1", "MY_COMMAND1", cset->getLastCommandSent()->getText());
+
+ cset->writeToSocket(sok, tracer);
+ VASSERT_EQ("Cmd 2", "MY_COMMAND2", cset->getLastCommandSent()->getText());
+ }
+
+ void testGetLastCommandSentPipeline() {
+
+ vmime::shared_ptr <SMTPCommandSet> cset = SMTPCommandSet::create(/* pipelining */ true);
+
+ cset->addCommand(SMTPCommand::createCommand("MY_COMMAND1"));
+ cset->addCommand(SMTPCommand::createCommand("MY_COMMAND2"));
+
+ vmime::shared_ptr <vmime::net::tracer> tracer;
+ vmime::shared_ptr <testSocket> sok = vmime::make_shared <testSocket>();
+
+ cset->writeToSocket(sok, tracer);
+ VASSERT_EQ("Cmd 1", "MY_COMMAND1", cset->getLastCommandSent()->getText());
+
+ cset->writeToSocket(sok, tracer);
+ VASSERT_EQ("Cmd 2", "MY_COMMAND2", cset->getLastCommandSent()->getText());
+ }
+
+VMIME_TEST_SUITE_END
diff --git a/vmime-master/tests/net/smtp/SMTPCommandTest.cpp b/vmime-master/tests/net/smtp/SMTPCommandTest.cpp
new file mode 100644
index 0000000..ecaf292
--- /dev/null
+++ b/vmime-master/tests/net/smtp/SMTPCommandTest.cpp
@@ -0,0 +1,252 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "tests/testUtils.hpp"
+
+#include "vmime/net/smtp/SMTPCommand.hpp"
+
+
+using namespace vmime::net::smtp;
+
+
+VMIME_TEST_SUITE_BEGIN(SMTPCommandTest)
+
+ VMIME_TEST_LIST_BEGIN
+ VMIME_TEST(testCreateCommand)
+ VMIME_TEST(testCreateCommandParams)
+ VMIME_TEST(testHELO)
+ VMIME_TEST(testEHLO)
+ VMIME_TEST(testAUTH)
+ VMIME_TEST(testAUTH_InitialResponse)
+ VMIME_TEST(testSTARTTLS)
+ VMIME_TEST(testMAIL)
+ VMIME_TEST(testMAIL_Encoded)
+ VMIME_TEST(testMAIL_UTF8)
+ VMIME_TEST(testMAIL_SIZE)
+ VMIME_TEST(testMAIL_SIZE_UTF8)
+ VMIME_TEST(testRCPT)
+ VMIME_TEST(testRCPT_Encoded)
+ VMIME_TEST(testRCPT_UTF8)
+ VMIME_TEST(testRSET)
+ VMIME_TEST(testDATA)
+ VMIME_TEST(testBDAT)
+ VMIME_TEST(testNOOP)
+ VMIME_TEST(testQUIT)
+ VMIME_TEST(testWriteToSocket)
+ VMIME_TEST_LIST_END
+
+
+ void testCreateCommand() {
+
+ vmime::shared_ptr <SMTPCommand> cmd = SMTPCommand::createCommand("MY_COMMAND");
+
+ VASSERT_NOT_NULL("Not null", cmd);
+ VASSERT_EQ("Text", "MY_COMMAND", cmd->getText());
+ }
+
+ void testCreateCommandParams() {
+
+ vmime::shared_ptr <SMTPCommand> cmd = SMTPCommand::createCommand("MY_COMMAND param1 param2");
+
+ VASSERT_NOT_NULL("Not null", cmd);
+ VASSERT_EQ("Text", "MY_COMMAND param1 param2", cmd->getText());
+ }
+
+ void testHELO() {
+
+ vmime::shared_ptr <SMTPCommand> cmd = SMTPCommand::HELO("hostname");
+
+ VASSERT_NOT_NULL("Not null", cmd);
+ VASSERT_EQ("Text", "HELO hostname", cmd->getText());
+ }
+
+ void testEHLO() {
+
+ vmime::shared_ptr <SMTPCommand> cmd = SMTPCommand::EHLO("hostname");
+
+ VASSERT_NOT_NULL("Not null", cmd);
+ VASSERT_EQ("Text", "EHLO hostname", cmd->getText());
+ }
+
+ void testAUTH() {
+
+ vmime::shared_ptr <SMTPCommand> cmd = SMTPCommand::AUTH("saslmechanism");
+
+ VASSERT_NOT_NULL("Not null", cmd);
+ VASSERT_EQ("Text", "AUTH saslmechanism", cmd->getText());
+ }
+
+ void testAUTH_InitialResponse() {
+
+ vmime::shared_ptr <SMTPCommand> cmd = SMTPCommand::AUTH("saslmechanism", "initial-response");
+
+ VASSERT_NOT_NULL("Not null", cmd);
+ VASSERT_EQ("Text", "AUTH saslmechanism initial-response", cmd->getText());
+ }
+
+ void testSTARTTLS() {
+
+ vmime::shared_ptr <SMTPCommand> cmd = SMTPCommand::STARTTLS();
+
+ VASSERT_NOT_NULL("Not null", cmd);
+ VASSERT_EQ("Text", "STARTTLS", cmd->getText());
+ }
+
+ void testMAIL() {
+
+ vmime::shared_ptr <SMTPCommand> cmd = SMTPCommand::MAIL(vmime::mailbox("me@vmime.org"), false, "FULL", "dsn-unique-id");
+
+ VASSERT_NOT_NULL("Not null", cmd);
+ VASSERT_EQ("Text", "MAIL FROM:<me@vmime.org> RET=FULL ENVID=<dsn-unique-id>", cmd->getText());
+ }
+
+ void testMAIL_Encoded() {
+
+ vmime::shared_ptr <SMTPCommand> cmd = SMTPCommand::MAIL(
+ vmime::mailbox(vmime::emailAddress("mailtest", "例え.テスト")), false, "FULL", "dsn-unique-id"
+ );
+
+ VASSERT_NOT_NULL("Not null", cmd);
+ VASSERT_EQ("Text", "MAIL FROM:<mailtest@xn--r8jz45g.xn--zckzah> RET=FULL ENVID=<dsn-unique-id>", cmd->getText());
+ }
+
+ void testMAIL_UTF8() {
+
+ vmime::shared_ptr <SMTPCommand> cmd = SMTPCommand::MAIL(
+ vmime::mailbox(vmime::emailAddress("mailtest", "例え.テスト")), true, "FULL", "dsn-unique-id"
+ );
+
+ VASSERT_NOT_NULL("Not null", cmd);
+ VASSERT_EQ("Text", "MAIL FROM:<mailtest@例え.テスト> RET=FULL ENVID=<dsn-unique-id> SMTPUTF8", cmd->getText());
+ }
+
+ void testMAIL_SIZE() {
+
+ vmime::shared_ptr <SMTPCommand> cmd = SMTPCommand::MAIL(
+ vmime::mailbox("me@vmime.org"), false, 123456789, "FULL", "dsn-unique-id"
+ );
+
+ VASSERT_NOT_NULL("Not null", cmd);
+ VASSERT_EQ("Text", "MAIL FROM:<me@vmime.org> RET=FULL ENVID=<dsn-unique-id> SIZE=123456789", cmd->getText());
+ }
+
+ void testMAIL_SIZE_UTF8() {
+
+ vmime::shared_ptr <SMTPCommand> cmd = SMTPCommand::MAIL(
+ vmime::mailbox(vmime::emailAddress("mailtest", "例え.テスト")), true, 123456789, "FULL", "dsn-unique-id"
+ );
+
+ VASSERT_NOT_NULL("Not null", cmd);
+ VASSERT_EQ("Text", "MAIL FROM:<mailtest@例え.テスト> RET=FULL ENVID=<dsn-unique-id> SMTPUTF8 SIZE=123456789", cmd->getText());
+ }
+
+ void testRCPT() {
+
+ vmime::shared_ptr <SMTPCommand> cmd =
+ SMTPCommand::RCPT(vmime::mailbox("someone@vmime.org"), false, "NEVER");
+
+ VASSERT_NOT_NULL("Not null", cmd);
+ VASSERT_EQ("Text", "RCPT TO:<someone@vmime.org> NOTIFY=NEVER", cmd->getText());
+ }
+
+ void testRCPT_Encoded() {
+
+ vmime::shared_ptr <SMTPCommand> cmd = SMTPCommand::RCPT(
+ vmime::mailbox(vmime::emailAddress("mailtest", "例え.テスト")), false, "NEVER"
+ );
+
+ VASSERT_NOT_NULL("Not null", cmd);
+ VASSERT_EQ("Text", "RCPT TO:<mailtest@xn--r8jz45g.xn--zckzah> NOTIFY=NEVER", cmd->getText());
+ }
+
+ void testRCPT_UTF8() {
+
+ vmime::shared_ptr <SMTPCommand> cmd = SMTPCommand::RCPT(
+ vmime::mailbox(vmime::emailAddress("mailtest", "例え.テスト")), true, "NEVER"
+ );
+
+ VASSERT_NOT_NULL("Not null", cmd);
+ VASSERT_EQ("Text", "RCPT TO:<mailtest@例え.テスト> NOTIFY=NEVER", cmd->getText());
+ }
+
+ void testRSET() {
+
+ vmime::shared_ptr <SMTPCommand> cmd = SMTPCommand::RSET();
+
+ VASSERT_NOT_NULL("Not null", cmd);
+ VASSERT_EQ("Text", "RSET", cmd->getText());
+ }
+
+ void testDATA() {
+
+ vmime::shared_ptr <SMTPCommand> cmd = SMTPCommand::DATA();
+
+ VASSERT_NOT_NULL("Not null", cmd);
+ VASSERT_EQ("Text", "DATA", cmd->getText());
+ }
+
+ void testBDAT() {
+
+ vmime::shared_ptr <SMTPCommand> cmd1 = SMTPCommand::BDAT(12345, false);
+
+ VASSERT_NOT_NULL("Not null", cmd1);
+ VASSERT_EQ("Text", "BDAT 12345", cmd1->getText());
+
+ vmime::shared_ptr <SMTPCommand> cmd2 = SMTPCommand::BDAT(67890, true);
+
+ VASSERT_NOT_NULL("Not null", cmd2);
+ VASSERT_EQ("Text", "BDAT 67890 LAST", cmd2->getText());
+ }
+
+ void testNOOP() {
+
+ vmime::shared_ptr <SMTPCommand> cmd = SMTPCommand::NOOP();
+
+ VASSERT_NOT_NULL("Not null", cmd);
+ VASSERT_EQ("Text", "NOOP", cmd->getText());
+ }
+
+ void testQUIT() {
+
+ vmime::shared_ptr <SMTPCommand> cmd = SMTPCommand::QUIT();
+
+ VASSERT_NOT_NULL("Not null", cmd);
+ VASSERT_EQ("Text", "QUIT", cmd->getText());
+ }
+
+ void testWriteToSocket() {
+
+ vmime::shared_ptr <SMTPCommand> cmd = SMTPCommand::createCommand("MY_COMMAND param1 param2");
+
+ vmime::shared_ptr <vmime::net::tracer> tracer;
+ vmime::shared_ptr <testSocket> sok = vmime::make_shared <testSocket>();
+
+ cmd->writeToSocket(sok, tracer);
+
+ vmime::string response;
+ sok->localReceive(response);
+
+ VASSERT_EQ("Sent buffer", "MY_COMMAND param1 param2\r\n", response);
+ }
+
+VMIME_TEST_SUITE_END
diff --git a/vmime-master/tests/net/smtp/SMTPResponseTest.cpp b/vmime-master/tests/net/smtp/SMTPResponseTest.cpp
new file mode 100644
index 0000000..f899a82
--- /dev/null
+++ b/vmime-master/tests/net/smtp/SMTPResponseTest.cpp
@@ -0,0 +1,238 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "tests/testUtils.hpp"
+
+#include "vmime/net/smtp/SMTPResponse.hpp"
+
+
+VMIME_TEST_SUITE_BEGIN(SMTPResponseTest)
+
+ VMIME_TEST_LIST_BEGIN
+ VMIME_TEST(testSingleLineResponse)
+ VMIME_TEST(testSingleLineResponseLF)
+ VMIME_TEST(testMultiLineResponse)
+ VMIME_TEST(testMultiLineResponseDifferentCode)
+ VMIME_TEST(testIncompleteMultiLineResponse)
+ VMIME_TEST(testNoResponseText)
+ VMIME_TEST(testEnhancedStatusCode)
+ VMIME_TEST(testNoEnhancedStatusCode)
+ VMIME_TEST(testInvalidEnhancedStatusCode)
+ VMIME_TEST_LIST_END
+
+
+ void testSingleLineResponse() {
+
+ vmime::shared_ptr <vmime::net::tracer> tracer;
+ vmime::shared_ptr <testSocket> socket = vmime::make_shared <testSocket>();
+ vmime::shared_ptr <vmime::net::timeoutHandler> toh = vmime::make_shared <testTimeoutHandler>();
+
+ socket->localSend("123 Response Text\r\n");
+
+ vmime::net::smtp::SMTPResponse::state responseState;
+
+ vmime::shared_ptr <vmime::net::smtp::SMTPResponse> resp =
+ vmime::net::smtp::SMTPResponse::readResponse(tracer, socket, toh, responseState);
+
+ VASSERT_EQ("Code", 123, resp->getCode());
+ VASSERT_EQ("Lines", 1, resp->getLineCount());
+ VASSERT_EQ("Text", "Response Text", resp->getText());
+ }
+
+ void testSingleLineResponseLF() {
+
+ vmime::shared_ptr <vmime::net::tracer> tracer;
+ vmime::shared_ptr <testSocket> socket = vmime::make_shared <testSocket>();
+ vmime::shared_ptr <vmime::net::timeoutHandler> toh = vmime::make_shared <testTimeoutHandler>();
+
+ socket->localSend("123 Response Text\n");
+
+ vmime::net::smtp::SMTPResponse::state responseState;
+
+ vmime::shared_ptr <vmime::net::smtp::SMTPResponse> resp =
+ vmime::net::smtp::SMTPResponse::readResponse(tracer, socket, toh, responseState);
+
+ VASSERT_EQ("Code", 123, resp->getCode());
+ VASSERT_EQ("Lines", 1, resp->getLineCount());
+ VASSERT_EQ("Text", "Response Text", resp->getText());
+ }
+
+ void testMultiLineResponse() {
+
+ vmime::shared_ptr <vmime::net::tracer> tracer;
+ vmime::shared_ptr <testSocket> socket = vmime::make_shared <testSocket>();
+ vmime::shared_ptr <vmime::net::timeoutHandler> toh = vmime::make_shared <testTimeoutHandler>();
+
+ socket->localSend(
+ "123-Response\r\n"
+ "123 Text\r\n"
+ );
+
+ vmime::net::smtp::SMTPResponse::state responseState;
+
+ vmime::shared_ptr <vmime::net::smtp::SMTPResponse> resp =
+ vmime::net::smtp::SMTPResponse::readResponse(tracer, socket, toh, responseState);
+
+ VASSERT_EQ("Code", 123, resp->getCode());
+ VASSERT_EQ("Lines", 2, resp->getLineCount());
+ VASSERT_EQ("Text", "Response\nText", resp->getText());
+
+ VASSERT_EQ("Code", 123, resp->getLineAt(0).getCode());
+ VASSERT_EQ("Text", "Response", resp->getLineAt(0).getText());
+
+ VASSERT_EQ("Code", 123, resp->getLineAt(1).getCode());
+ VASSERT_EQ("Text", "Text", resp->getLineAt(1).getText());
+ }
+
+ void testMultiLineResponseDifferentCode() {
+
+ vmime::shared_ptr <vmime::net::tracer> tracer;
+ vmime::shared_ptr <testSocket> socket = vmime::make_shared <testSocket>();
+ vmime::shared_ptr <vmime::net::timeoutHandler> toh = vmime::make_shared <testTimeoutHandler>();
+
+ socket->localSend(
+ "123-Response\r\n"
+ "456 Text\r\n"
+ );
+
+ vmime::net::smtp::SMTPResponse::state responseState;
+
+ vmime::shared_ptr <vmime::net::smtp::SMTPResponse> resp =
+ vmime::net::smtp::SMTPResponse::readResponse(tracer, socket, toh, responseState);
+
+ VASSERT_EQ("Code", 0, resp->getCode());
+ VASSERT_EQ("Lines", 2, resp->getLineCount());
+ VASSERT_EQ("Text", "Response\nText", resp->getText());
+
+ VASSERT_EQ("Code", 123, resp->getLineAt(0).getCode());
+ VASSERT_EQ("Text", "Response", resp->getLineAt(0).getText());
+
+ VASSERT_EQ("Code", 456, resp->getLineAt(1).getCode());
+ VASSERT_EQ("Text", "Text", resp->getLineAt(1).getText());
+ }
+
+ void testIncompleteMultiLineResponse() {
+
+ vmime::shared_ptr <vmime::net::tracer> tracer;
+ vmime::shared_ptr <testSocket> socket = vmime::make_shared <testSocket>();
+ vmime::shared_ptr <vmime::net::timeoutHandler> toh = vmime::make_shared <testTimeoutHandler>(1);
+
+ socket->localSend(
+ "123-Response\r\n"
+ "123-Text\r\n"
+ // Missing data
+ );
+
+ vmime::net::smtp::SMTPResponse::state responseState;
+
+ VASSERT_THROW(
+ "Incomplete response",
+ vmime::net::smtp::SMTPResponse::readResponse(tracer, socket, toh, responseState),
+ vmime::exceptions::operation_timed_out
+ );
+ }
+
+ void testNoResponseText() {
+
+ vmime::shared_ptr <vmime::net::tracer> tracer;
+ vmime::shared_ptr <testSocket> socket = vmime::make_shared <testSocket>();
+ vmime::shared_ptr <vmime::net::timeoutHandler> toh = vmime::make_shared <testTimeoutHandler>(1);
+
+ socket->localSend(
+ "250\r\n"
+ );
+
+ vmime::net::smtp::SMTPResponse::state responseState;
+
+ vmime::shared_ptr <vmime::net::smtp::SMTPResponse> resp =
+ vmime::net::smtp::SMTPResponse::readResponse(tracer, socket, toh, responseState);
+
+ VASSERT_EQ("Code", 250, resp->getCode());
+ VASSERT_EQ("Lines", 1, resp->getLineCount());
+ VASSERT_EQ("Text", "", resp->getText());
+ }
+
+ void testEnhancedStatusCode() {
+
+ vmime::shared_ptr <vmime::net::tracer> tracer;
+ vmime::shared_ptr <testSocket> socket = vmime::make_shared <testSocket>();
+ vmime::shared_ptr <vmime::net::timeoutHandler> toh = vmime::make_shared <testTimeoutHandler>();
+
+ socket->localSend("250 2.1.5 OK fu13sm4720601wic.7 - gsmtp\r\n");
+
+ vmime::net::smtp::SMTPResponse::state responseState;
+
+ vmime::shared_ptr <vmime::net::smtp::SMTPResponse> resp =
+ vmime::net::smtp::SMTPResponse::readResponse(tracer, socket, toh, responseState);
+
+ VASSERT_EQ("Code", 250, resp->getCode());
+ VASSERT_EQ("Lines", 1, resp->getLineCount());
+ VASSERT_EQ("Text", "2.1.5 OK fu13sm4720601wic.7 - gsmtp", resp->getText());
+ VASSERT_EQ("Enh.class", 2, resp->getEnhancedCode().klass);
+ VASSERT_EQ("Enh.subject", 1, resp->getEnhancedCode().subject);
+ VASSERT_EQ("Enh.detail", 5, resp->getEnhancedCode().detail);
+ }
+
+ void testNoEnhancedStatusCode() {
+
+ vmime::shared_ptr <vmime::net::tracer> tracer;
+ vmime::shared_ptr <testSocket> socket = vmime::make_shared <testSocket>();
+ vmime::shared_ptr <vmime::net::timeoutHandler> toh = vmime::make_shared <testTimeoutHandler>();
+
+ socket->localSend("354 Go ahead fu13sm4720601wic.7 - gsmtp\r\n");
+
+ vmime::net::smtp::SMTPResponse::state responseState;
+
+ vmime::shared_ptr <vmime::net::smtp::SMTPResponse> resp =
+ vmime::net::smtp::SMTPResponse::readResponse(tracer, socket, toh, responseState);
+
+ VASSERT_EQ("Code", 354, resp->getCode());
+ VASSERT_EQ("Lines", 1, resp->getLineCount());
+ VASSERT_EQ("Text", "Go ahead fu13sm4720601wic.7 - gsmtp", resp->getText());
+ VASSERT_EQ("Enh.class", 0, resp->getEnhancedCode().klass);
+ VASSERT_EQ("Enh.subject", 0, resp->getEnhancedCode().subject);
+ VASSERT_EQ("Enh.detail", 0, resp->getEnhancedCode().detail);
+ }
+
+ void testInvalidEnhancedStatusCode() {
+
+ vmime::shared_ptr <vmime::net::tracer> tracer;
+ vmime::shared_ptr <testSocket> socket = vmime::make_shared <testSocket>();
+ vmime::shared_ptr <vmime::net::timeoutHandler> toh = vmime::make_shared <testTimeoutHandler>();
+
+ socket->localSend("250 4.2 xxx\r\n");
+
+ vmime::net::smtp::SMTPResponse::state responseState;
+
+ vmime::shared_ptr <vmime::net::smtp::SMTPResponse> resp =
+ vmime::net::smtp::SMTPResponse::readResponse(tracer, socket, toh, responseState);
+
+ VASSERT_EQ("Code", 250, resp->getCode());
+ VASSERT_EQ("Lines", 1, resp->getLineCount());
+ VASSERT_EQ("Text", "4.2 xxx", resp->getText());
+ VASSERT_EQ("Enh.class", 0, resp->getEnhancedCode().klass);
+ VASSERT_EQ("Enh.subject", 0, resp->getEnhancedCode().subject);
+ VASSERT_EQ("Enh.detail", 0, resp->getEnhancedCode().detail);
+ }
+
+VMIME_TEST_SUITE_END
diff --git a/vmime-master/tests/net/smtp/SMTPTransportTest.cpp b/vmime-master/tests/net/smtp/SMTPTransportTest.cpp
new file mode 100644
index 0000000..8ea4ba7
--- /dev/null
+++ b/vmime-master/tests/net/smtp/SMTPTransportTest.cpp
@@ -0,0 +1,324 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "tests/testUtils.hpp"
+
+#include "vmime/net/smtp/SMTPTransport.hpp"
+#include "vmime/net/smtp/SMTPChunkingOutputStreamAdapter.hpp"
+#include "vmime/net/smtp/SMTPExceptions.hpp"
+
+#include "SMTPTransportTestUtils.hpp"
+
+
+VMIME_TEST_SUITE_BEGIN(SMTPTransportTest)
+
+ VMIME_TEST_LIST_BEGIN
+ VMIME_TEST(testConnectToInvalidServer)
+ VMIME_TEST(testGreetingError)
+ VMIME_TEST(testMAILandRCPT)
+ VMIME_TEST(testChunking)
+ VMIME_TEST(testSize_Chunking)
+ VMIME_TEST(testSize_NoChunking)
+ VMIME_TEST(testSMTPUTF8_available)
+ VMIME_TEST(testSMTPUTF8_notAvailable)
+ VMIME_TEST_LIST_END
+
+
+ void testConnectToInvalidServer() {
+
+ vmime::shared_ptr <vmime::net::session> sess = vmime::net::session::create();
+
+ vmime::utility::url url("smtp://invalid-smtp-server");
+ vmime::shared_ptr <vmime::net::transport> store = sess->getTransport(url);
+
+ VASSERT_THROW("connect", store->connect(), vmime::exceptions::connection_error);
+ }
+
+ void testGreetingError() {
+
+ vmime::shared_ptr <vmime::net::session> session = vmime::net::session::create();
+
+ vmime::shared_ptr <vmime::net::transport> tr =
+ session->getTransport(vmime::utility::url("smtp://localhost"));
+
+ tr->setSocketFactory(vmime::make_shared <testSocketFactory <greetingErrorSMTPTestSocket> >());
+ tr->setTimeoutHandlerFactory(vmime::make_shared <testTimeoutHandlerFactory>());
+
+ VASSERT_THROW(
+ "Connection",
+ tr->connect(),
+ vmime::exceptions::connection_greeting_error
+ );
+ }
+
+ void testMAILandRCPT() {
+
+ vmime::shared_ptr <vmime::net::session> session = vmime::net::session::create();
+
+ vmime::shared_ptr <vmime::net::transport> tr =
+ session->getTransport(vmime::utility::url("smtp://localhost"));
+
+ tr->setSocketFactory(vmime::make_shared <testSocketFactory <MAILandRCPTSMTPTestSocket> >());
+ tr->setTimeoutHandlerFactory(vmime::make_shared <testTimeoutHandlerFactory>());
+
+ VASSERT_NO_THROW("Connection", tr->connect());
+
+ vmime::mailbox exp("expeditor@test.vmime.org");
+
+ vmime::mailboxList recips;
+ recips.appendMailbox(vmime::make_shared <vmime::mailbox>("recipient1@test.vmime.org"));
+ recips.appendMailbox(vmime::make_shared <vmime::mailbox>("recipient2@test.vmime.org"));
+ recips.appendMailbox(vmime::make_shared <vmime::mailbox>("recipient3@test.vmime.org"));
+
+ vmime::string data("Message data");
+ vmime::utility::inputStreamStringAdapter is(data);
+
+ tr->send(exp, recips, is, 0);
+ }
+
+ void testChunking() {
+
+ vmime::shared_ptr <vmime::net::session> session = vmime::net::session::create();
+
+ vmime::shared_ptr <vmime::net::transport> tr =
+ session->getTransport(vmime::utility::url("smtp://localhost"));
+
+ tr->setSocketFactory(vmime::make_shared <testSocketFactory <chunkingSMTPTestSocket> >());
+ tr->setTimeoutHandlerFactory(vmime::make_shared <testTimeoutHandlerFactory>());
+
+ tr->connect();
+
+ VASSERT(
+ "Test server should report it supports the CHUNKING extension!",
+ vmime::dynamicCast <vmime::net::smtp::SMTPTransport>(tr)->getConnection()->hasExtension("CHUNKING")
+ );
+
+ vmime::mailbox exp("expeditor@test.vmime.org");
+
+ vmime::mailboxList recips;
+ recips.appendMailbox(vmime::make_shared <vmime::mailbox>("recipient@test.vmime.org"));
+
+ vmime::shared_ptr <vmime::message> msg = vmime::make_shared <SMTPTestMessage>();
+
+ tr->send(msg, exp, recips);
+ }
+
+ void testSize_Chunking() {
+
+ vmime::shared_ptr <vmime::net::session> session = vmime::net::session::create();
+
+ vmime::shared_ptr <vmime::net::transport> tr =
+ session->getTransport(vmime::utility::url("smtp://localhost"));
+
+ tr->setSocketFactory(vmime::make_shared <testSocketFactory <bigMessageSMTPTestSocket <true> > >());
+ tr->setTimeoutHandlerFactory(vmime::make_shared <testTimeoutHandlerFactory>());
+
+ tr->connect();
+
+ VASSERT(
+ "Test server should report it supports the SIZE extension!",
+ vmime::dynamicCast <vmime::net::smtp::SMTPTransport>(tr)->getConnection()->hasExtension("SIZE")
+ );
+
+ vmime::mailbox exp("expeditor@test.vmime.org");
+
+ vmime::mailboxList recips;
+ recips.appendMailbox(vmime::make_shared <vmime::mailbox>("recipient@test.vmime.org"));
+
+ vmime::shared_ptr <vmime::message> msg = vmime::make_shared <SMTPBigTestMessage4MB>();
+
+ VASSERT_THROW(
+ "Max size limit exception",
+ tr->send(msg, exp, recips),
+ vmime::net::smtp::SMTPMessageSizeExceedsMaxLimitsException
+ );
+ }
+
+ void testSize_NoChunking() {
+
+ vmime::shared_ptr <vmime::net::session> session = vmime::net::session::create();
+
+ vmime::shared_ptr <vmime::net::transport> tr =
+ session->getTransport(vmime::utility::url("smtp://localhost"));
+
+ tr->setSocketFactory(vmime::make_shared <testSocketFactory <bigMessageSMTPTestSocket <false> > >());
+ tr->setTimeoutHandlerFactory(vmime::make_shared <testTimeoutHandlerFactory>());
+
+ tr->connect();
+
+ VASSERT(
+ "Test server should report it supports the SIZE extension!",
+ vmime::dynamicCast <vmime::net::smtp::SMTPTransport>(tr)->getConnection()->hasExtension("SIZE")
+ );
+
+ vmime::mailbox exp("expeditor@test.vmime.org");
+
+ vmime::mailboxList recips;
+ recips.appendMailbox(vmime::make_shared <vmime::mailbox>("recipient@test.vmime.org"));
+
+ vmime::shared_ptr <vmime::message> msg = vmime::make_shared <SMTPBigTestMessage4MB>();
+
+ VASSERT_THROW(
+ "Max size limit exception",
+ tr->send(msg, exp, recips),
+ vmime::net::smtp::SMTPMessageSizeExceedsMaxLimitsException
+ );
+ }
+
+ void testSMTPUTF8_available() {
+
+ // Test with UTF8 sender
+ {
+ vmime::shared_ptr <vmime::net::session> session = vmime::net::session::create();
+
+ vmime::shared_ptr <vmime::net::transport> tr =
+ session->getTransport(vmime::utility::url("smtp://localhost"));
+
+ tr->setSocketFactory(vmime::make_shared <testSocketFactory <UTF8SMTPTestSocket <true> > >());
+ tr->setTimeoutHandlerFactory(vmime::make_shared <testTimeoutHandlerFactory>());
+
+ VASSERT_NO_THROW("Connection", tr->connect());
+
+ vmime::mailbox exp(
+ vmime::emailAddress(
+ vmime::word("expéditeur", vmime::charsets::UTF_8),
+ vmime::word("test.vmime.org")
+ )
+ );
+
+ vmime::mailboxList recips;
+ recips.appendMailbox(vmime::make_shared <vmime::mailbox>("recipient1@test.vmime.org"));
+ recips.appendMailbox(vmime::make_shared <vmime::mailbox>("recipient2@test.vmime.org"));
+ recips.appendMailbox(vmime::make_shared <vmime::mailbox>(
+ vmime::emailAddress(
+ vmime::word("récepteur", vmime::charsets::UTF_8),
+ vmime::word("test.vmime.org")
+ )
+ ));
+
+ vmime::string data("Message data");
+ vmime::utility::inputStreamStringAdapter is(data);
+
+ tr->send(exp, recips, is, 0);
+ }
+
+ // Test with UTF8 recipient only
+ {
+ vmime::shared_ptr <vmime::net::session> session = vmime::net::session::create();
+
+ vmime::shared_ptr <vmime::net::transport> tr =
+ session->getTransport(vmime::utility::url("smtp://localhost"));
+
+ tr->setSocketFactory(vmime::make_shared <testSocketFactory <UTF8SMTPTestSocket <true> > >());
+ tr->setTimeoutHandlerFactory(vmime::make_shared <testTimeoutHandlerFactory>());
+
+ VASSERT_NO_THROW("Connection", tr->connect());
+
+ vmime::mailbox exp("expediteur@test.vmime.org");
+
+ vmime::mailboxList recips;
+ recips.appendMailbox(vmime::make_shared <vmime::mailbox>("recipient1@test.vmime.org"));
+ recips.appendMailbox(vmime::make_shared <vmime::mailbox>("recipient2@test.vmime.org"));
+ recips.appendMailbox(vmime::make_shared <vmime::mailbox>(
+ vmime::emailAddress(
+ vmime::word("récepteur", vmime::charsets::UTF_8),
+ vmime::word("test.vmime.org")
+ )
+ ));
+
+ vmime::string data("Message data");
+ vmime::utility::inputStreamStringAdapter is(data);
+
+ tr->send(exp, recips, is, 0);
+ }
+ }
+
+ void testSMTPUTF8_notAvailable() {
+
+ // Test with UTF8 sender
+ {
+ vmime::shared_ptr <vmime::net::session> session = vmime::net::session::create();
+
+ vmime::shared_ptr <vmime::net::transport> tr =
+ session->getTransport(vmime::utility::url("smtp://localhost"));
+
+ tr->setSocketFactory(vmime::make_shared <testSocketFactory <UTF8SMTPTestSocket <false> > >());
+ tr->setTimeoutHandlerFactory(vmime::make_shared <testTimeoutHandlerFactory>());
+
+ VASSERT_NO_THROW("Connection", tr->connect());
+
+ vmime::mailbox exp(
+ vmime::emailAddress(
+ vmime::word("expéditeur", vmime::charsets::UTF_8),
+ vmime::word("test.vmime.org")
+ )
+ );
+
+ vmime::mailboxList recips;
+ recips.appendMailbox(vmime::make_shared <vmime::mailbox>("recipient1@test.vmime.org"));
+ recips.appendMailbox(vmime::make_shared <vmime::mailbox>("recipient2@test.vmime.org"));
+ recips.appendMailbox(vmime::make_shared <vmime::mailbox>(
+ vmime::emailAddress(
+ vmime::word("récepteur", vmime::charsets::UTF_8),
+ vmime::word("test.vmime.org")
+ )
+ ));
+
+ vmime::string data("Message data");
+ vmime::utility::inputStreamStringAdapter is(data);
+
+ tr->send(exp, recips, is, 0);
+ }
+
+ // Test with UTF8 recipient only
+ {
+ vmime::shared_ptr <vmime::net::session> session = vmime::net::session::create();
+
+ vmime::shared_ptr <vmime::net::transport> tr =
+ session->getTransport(vmime::utility::url("smtp://localhost"));
+
+ tr->setSocketFactory(vmime::make_shared <testSocketFactory <UTF8SMTPTestSocket <false> > >());
+ tr->setTimeoutHandlerFactory(vmime::make_shared <testTimeoutHandlerFactory>());
+
+ VASSERT_NO_THROW("Connection", tr->connect());
+
+ vmime::mailbox exp("expediteur@test.vmime.org");
+
+ vmime::mailboxList recips;
+ recips.appendMailbox(vmime::make_shared <vmime::mailbox>("recipient1@test.vmime.org"));
+ recips.appendMailbox(vmime::make_shared <vmime::mailbox>("recipient2@test.vmime.org"));
+ recips.appendMailbox(vmime::make_shared <vmime::mailbox>(
+ vmime::emailAddress(
+ vmime::word("récepteur", vmime::charsets::UTF_8),
+ vmime::word("test.vmime.org")
+ )
+ ));
+
+ vmime::string data("Message data");
+ vmime::utility::inputStreamStringAdapter is(data);
+
+ tr->send(exp, recips, is, 0);
+ }
+ }
+
+VMIME_TEST_SUITE_END
diff --git a/vmime-master/tests/net/smtp/SMTPTransportTestUtils.hpp b/vmime-master/tests/net/smtp/SMTPTransportTestUtils.hpp
new file mode 100644
index 0000000..8710639
--- /dev/null
+++ b/vmime-master/tests/net/smtp/SMTPTransportTestUtils.hpp
@@ -0,0 +1,792 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+
+/** Accepts connection and fails on greeting.
+ */
+class greetingErrorSMTPTestSocket : public lineBasedTestSocket {
+
+public:
+
+ void onConnected() {
+
+ localSend("421 test.vmime.org Service not available, closing transmission channel\r\n");
+ disconnect();
+ }
+
+ void processCommand() {
+
+ if (!haveMoreLines()) {
+ return;
+ }
+
+ getNextLine();
+
+ localSend("502 Command not implemented\r\n");
+ processCommand();
+ }
+};
+
+
+/** SMTP test server 1.
+ *
+ * Test send().
+ * Ensure MAIL and RCPT commands are sent correctly.
+ */
+class MAILandRCPTSMTPTestSocket : public lineBasedTestSocket {
+
+public:
+
+ MAILandRCPTSMTPTestSocket() {
+
+ m_recipients.insert("recipient1@test.vmime.org");
+ m_recipients.insert("recipient2@test.vmime.org");
+ m_recipients.insert("recipient3@test.vmime.org");
+
+ m_state = STATE_NOT_CONNECTED;
+ m_ehloSent = m_heloSent = m_mailSent = m_rcptSent = m_dataSent = m_quitSent = false;
+ }
+
+ ~MAILandRCPTSMTPTestSocket() {
+
+ VASSERT("Client must send the DATA command", m_dataSent);
+ VASSERT("Client must send the QUIT command", m_quitSent);
+ }
+
+ void onConnected() {
+
+ localSend("220 test.vmime.org Service ready\r\n");
+ processCommand();
+
+ m_state = STATE_COMMAND;
+ }
+
+ void processCommand() {
+
+ if (!haveMoreLines()) {
+ return;
+ }
+
+ vmime::string line = getNextLine();
+ std::istringstream iss(line);
+
+ switch (m_state) {
+
+ case STATE_NOT_CONNECTED:
+
+ localSend("451 Requested action aborted: invalid state\r\n");
+ break;
+
+ case STATE_COMMAND: {
+
+ std::string cmd;
+ iss >> cmd;
+
+ if (cmd.empty()) {
+
+ localSend("500 Syntax error, command unrecognized\r\n");
+
+ } else if (cmd == "EHLO") {
+
+ localSend("502 Command not implemented\r\n");
+
+ m_ehloSent = true;
+
+ } else if (cmd == "HELO") {
+
+ VASSERT("Client must send the EHLO command before HELO", m_ehloSent);
+
+ localSend("250 OK\r\n");
+
+ m_heloSent = true;
+
+ } else if (cmd == "MAIL") {
+
+ VASSERT("Client must send the HELO command", m_heloSent);
+ VASSERT("The MAIL command must be sent only one time", !m_mailSent);
+
+ VASSERT_EQ("MAIL", std::string("MAIL FROM:<expeditor@test.vmime.org>"), line);
+
+ localSend("250 OK\r\n");
+
+ m_mailSent = true;
+
+ } else if (cmd == "RCPT") {
+
+ const vmime::size_t lt = line.find('<');
+ const vmime::size_t gt = line.find('>');
+
+ VASSERT("RCPT <", lt != vmime::string::npos);
+ VASSERT("RCPT >", gt != vmime::string::npos);
+ VASSERT("RCPT ><", gt >= lt);
+
+ const vmime::string recip =
+ vmime::string(line.begin() + lt + 1, line.begin() + gt);
+
+ std::set <vmime::string>::iterator it =
+ m_recipients.find(recip);
+
+ VASSERT(
+ std::string("Recipient not found: '") + recip + "'",
+ it != m_recipients.end()
+ );
+
+ m_recipients.erase(it);
+
+ localSend("250 OK, recipient accepted\r\n");
+
+ m_rcptSent = true;
+
+ } else if (cmd == "DATA") {
+
+ VASSERT("Client must send the MAIL command", m_mailSent);
+ VASSERT("Client must send the RCPT command", m_rcptSent);
+ VASSERT("All recipients", m_recipients.empty());
+
+ localSend("354 Ready to accept data; end with <CRLF>.<CRLF>\r\n");
+
+ m_state = STATE_DATA;
+ m_msgData.clear();
+
+ m_dataSent = true;
+
+ } else if (cmd == "NOOP") {
+
+ localSend("250 Completed\r\n");
+
+ } else if (cmd == "QUIT") {
+
+ m_quitSent = true;
+
+ localSend("221 test.vmime.org Service closing transmission channel\r\n");
+
+ } else {
+
+ localSend("502 Command not implemented\r\n");
+ }
+
+ break;
+ }
+ case STATE_DATA: {
+
+ if (line == ".") {
+
+ VASSERT_EQ("Data", "Message data\r\n", m_msgData);
+
+ localSend("250 Message accepted for delivery\r\n");
+ m_state = STATE_COMMAND;
+
+ } else {
+
+ m_msgData += line + "\r\n";
+ }
+
+ break;
+ }
+
+ }
+
+ processCommand();
+ }
+
+private:
+
+ enum State {
+ STATE_NOT_CONNECTED,
+ STATE_COMMAND,
+ STATE_DATA
+ };
+
+ int m_state;
+
+ std::set <vmime::string> m_recipients;
+
+ std::string m_msgData;
+
+ bool m_ehloSent, m_heloSent, m_mailSent, m_rcptSent,
+ m_dataSent, m_quitSent;
+};
+
+
+
+/** SMTP test server 2.
+ *
+ * Test CHUNKING extension/BDAT command.
+ */
+class chunkingSMTPTestSocket : public testSocket {
+
+public:
+
+ chunkingSMTPTestSocket() {
+
+ m_state = STATE_NOT_CONNECTED;
+ m_bdatChunkCount = 0;
+ m_ehloSent = m_mailSent = m_rcptSent = m_quitSent = false;
+ }
+
+ ~chunkingSMTPTestSocket() {
+
+ VASSERT_EQ("BDAT chunk count", 3, m_bdatChunkCount);
+ VASSERT("Client must send the QUIT command", m_quitSent);
+ }
+
+ void onConnected() {
+
+ localSend("220 test.vmime.org Service ready\r\n");
+ processCommand();
+
+ m_state = STATE_COMMAND;
+ }
+
+ void onDataReceived() {
+
+ if (m_state == STATE_DATA) {
+
+ if (m_bdatChunkReceived != m_bdatChunkSize) {
+
+ const size_t remaining = m_bdatChunkSize - m_bdatChunkReceived;
+ const size_t received = localReceiveRaw(NULL, remaining);
+
+ m_bdatChunkReceived += received;
+ }
+
+ if (m_bdatChunkReceived == m_bdatChunkSize) {
+
+ m_state = STATE_COMMAND;
+ }
+ }
+
+ processCommand();
+ }
+
+ void processCommand() {
+
+ vmime::string line;
+
+ if (!localReceiveLine(line)) {
+ return;
+ }
+
+ std::istringstream iss(line);
+
+ switch (m_state) {
+
+ case STATE_NOT_CONNECTED:
+
+ localSend("451 Requested action aborted: invalid state\r\n");
+ break;
+
+ case STATE_COMMAND: {
+
+ std::string cmd;
+ iss >> cmd;
+
+ if (cmd == "EHLO") {
+
+ localSend("250-test.vmime.org says hello\r\n");
+ localSend("250 CHUNKING\r\n");
+
+ m_ehloSent = true;
+
+ } else if (cmd == "HELO") {
+
+ VASSERT("Client must not send the HELO command, as EHLO succeeded", false);
+
+ } else if (cmd == "MAIL") {
+
+ VASSERT("The MAIL command must be sent only one time", !m_mailSent);
+
+ localSend("250 OK\r\n");
+
+ m_mailSent = true;
+
+ } else if (cmd == "RCPT") {
+
+ localSend("250 OK, recipient accepted\r\n");
+
+ m_rcptSent = true;
+
+ } else if (cmd == "DATA") {
+
+ VASSERT("BDAT must be used here!", false);
+
+ } else if (cmd == "BDAT") {
+
+ VASSERT("Client must send the MAIL command", m_mailSent);
+ VASSERT("Client must send the RCPT command", m_rcptSent);
+
+ unsigned long chunkSize = 0;
+ iss >> chunkSize;
+
+ std::string last;
+ iss >> last;
+
+ if (m_bdatChunkCount == 0) {
+
+ VASSERT_EQ("BDAT chunk1 size", 262144, chunkSize);
+ VASSERT_EQ("BDAT chunk1 last", "", last);
+
+ } else if (m_bdatChunkCount == 1) {
+
+ VASSERT_EQ("BDAT chunk2 size", 262144, chunkSize);
+ VASSERT_EQ("BDAT chunk2 last", "", last);
+
+ } else if (m_bdatChunkCount == 2) {
+
+ VASSERT_EQ("BDAT chunk3 size", 4712, chunkSize);
+ VASSERT_EQ("BDAT chunk3 last", "LAST", last);
+
+ } else {
+
+ VASSERT("No more BDAT command should be issued!", false);
+ }
+
+ m_bdatChunkSize = chunkSize;
+ m_bdatChunkReceived = 0;
+ m_bdatChunkCount++;
+ m_state = STATE_DATA;
+
+ localSend("250 chunk received\r\n");
+
+ } else if (cmd == "NOOP") {
+
+ localSend("250 Completed\r\n");
+
+ } else if (cmd == "QUIT") {
+
+ localSend("221 test.vmime.org Service closing transmission channel\r\n");
+
+ m_quitSent = true;
+
+ } else {
+
+ localSend("502 Command not implemented\r\n");
+ }
+
+ break;
+ }
+
+ }
+
+ processCommand();
+ }
+
+private:
+
+ enum State {
+ STATE_NOT_CONNECTED,
+ STATE_COMMAND,
+ STATE_DATA
+ };
+
+ int m_state;
+ int m_bdatChunkCount;
+ size_t m_bdatChunkSize, m_bdatChunkReceived;
+
+ bool m_ehloSent, m_mailSent, m_rcptSent, m_quitSent;
+};
+
+
+class SMTPTestMessage : public vmime::message {
+
+public:
+
+ vmime::size_t getChunkBufferSize() const {
+
+ static vmime::net::smtp::SMTPChunkingOutputStreamAdapter chunkStream(vmime::null, 0, NULL);
+ return chunkStream.getBlockSize();
+ }
+
+ const std::vector <vmime::string>& getChunks() const {
+
+ static std::vector <vmime::string> chunks;
+
+ if (chunks.size() == 0) {
+ chunks.push_back(vmime::string(1000, 'A'));
+ chunks.push_back(vmime::string(3000, 'B'));
+ chunks.push_back(vmime::string(500000, 'C'));
+ chunks.push_back(vmime::string(25000, 'D'));
+ }
+
+ return chunks;
+ }
+
+ void generateImpl(
+ const vmime::generationContext& /* ctx */,
+ vmime::utility::outputStream& outputStream,
+ const size_t /* curLinePos */ = 0,
+ size_t* /* newLinePos */ = NULL
+ ) const {
+
+ for (size_t i = 0, n = getChunks().size() ; i < n ; ++i) {
+
+ const vmime::string& chunk = getChunks()[i];
+ outputStream.write(chunk.data(), chunk.size());
+ }
+ }
+};
+
+
+
+/** SMTP test server 3.
+ *
+ * Test SIZE extension.
+ */
+template <bool WITH_CHUNKING>
+class bigMessageSMTPTestSocket : public testSocket {
+
+public:
+
+ bigMessageSMTPTestSocket() {
+
+ m_state = STATE_NOT_CONNECTED;
+ m_ehloSent = m_mailSent = m_rcptSent = m_quitSent = false;
+ }
+
+ ~bigMessageSMTPTestSocket() {
+
+ VASSERT("Client must send the QUIT command", m_quitSent);
+ }
+
+ void onConnected() {
+
+ localSend("220 test.vmime.org Service ready\r\n");
+ processCommand();
+
+ m_state = STATE_COMMAND;
+ }
+
+ void onDataReceived() {
+
+ processCommand();
+ }
+
+ void processCommand() {
+
+ vmime::string line;
+
+ if (!localReceiveLine(line)) {
+ return;
+ }
+
+ std::istringstream iss(line);
+
+ switch (m_state) {
+
+ case STATE_NOT_CONNECTED:
+
+ localSend("451 Requested action aborted: invalid state\r\n");
+ break;
+
+ case STATE_COMMAND: {
+
+ std::string cmd;
+ iss >> cmd;
+
+ if (cmd == "EHLO") {
+
+ localSend("250-test.vmime.org says hello\r\n");
+
+ if (WITH_CHUNKING) {
+ localSend("250-CHUNKING\r\n");
+ }
+
+ localSend("250 SIZE 1000000\r\n");
+
+ m_ehloSent = true;
+
+ } else if (cmd == "HELO") {
+
+ VASSERT("Client must not send the HELO command, as EHLO succeeded", false);
+
+ } else if (cmd == "MAIL") {
+
+ VASSERT("The MAIL command must be sent only one time", !m_mailSent);
+
+ std::string address;
+ iss >> address;
+
+ VASSERT_EQ("MAIL/address", "FROM:<expeditor@test.vmime.org>", address);
+
+ std::string option;
+ iss >> option;
+
+ VASSERT_EQ("MAIL/size", "SIZE=4194304", option);
+
+ localSend("552 Channel size limit exceeded\r\n");
+
+ m_mailSent = true;
+
+ } else if (cmd == "NOOP") {
+
+ localSend("250 Completed\r\n");
+
+ } else if (cmd == "QUIT") {
+
+ localSend("221 test.vmime.org Service closing transmission channel\r\n");
+
+ m_quitSent = true;
+
+ } else {
+
+ VASSERT("No other command should be sent", false);
+
+ localSend("502 Command not implemented\r\n");
+ }
+
+ break;
+ }
+
+ }
+
+ processCommand();
+ }
+
+private:
+
+ enum State {
+ STATE_NOT_CONNECTED,
+ STATE_COMMAND,
+ STATE_DATA
+ };
+
+ int m_state;
+
+ bool m_ehloSent, m_mailSent, m_rcptSent, m_quitSent;
+};
+
+
+template <unsigned long SIZE>
+class SMTPBigTestMessage : public vmime::message {
+
+public:
+
+ size_t getGeneratedSize(const vmime::generationContext& /* ctx */) {
+
+ return SIZE;
+ }
+
+ void generateImpl(
+ const vmime::generationContext& /* ctx */,
+ vmime::utility::outputStream& outputStream,
+ const vmime::size_t /* curLinePos */ = 0,
+ vmime::size_t* /* newLinePos */ = NULL
+ ) const {
+
+ for (unsigned int i = 0, n = SIZE ; i < n ; ++i) {
+ outputStream.write("X", 1);
+ }
+ }
+};
+
+typedef SMTPBigTestMessage <4194304> SMTPBigTestMessage4MB;
+
+
+
+/** SMTP test server for SMTPUTF8 extension.
+ */
+template <bool SUPPORTS_UTF8>
+class UTF8SMTPTestSocket : public lineBasedTestSocket {
+
+public:
+
+ UTF8SMTPTestSocket() {
+
+ if (SUPPORTS_UTF8) {
+
+ m_rcptLines.insert("RCPT TO:<recipient1@test.vmime.org>");
+ m_rcptLines.insert("RCPT TO:<recipient2@test.vmime.org>");
+ m_rcptLines.insert("RCPT TO:<récepteur@test.vmime.org>");
+
+ } else {
+
+ m_rcptLines.insert("RCPT TO:<recipient1@test.vmime.org>");
+ m_rcptLines.insert("RCPT TO:<recipient2@test.vmime.org>");
+ m_rcptLines.insert("RCPT TO:<=?utf-8?Q?r=C3=A9cepteur?=@test.vmime.org>");
+ }
+
+ m_state = STATE_NOT_CONNECTED;
+ m_ehloSent = m_mailSent = m_rcptSent = m_dataSent = m_quitSent = false;
+ }
+
+ ~UTF8SMTPTestSocket() {
+
+ }
+
+ void onConnected() {
+
+ localSend("220 test.vmime.org Service ready\r\n");
+ processCommand();
+
+ m_state = STATE_COMMAND;
+ }
+
+ void processCommand() {
+
+ if (!haveMoreLines()) {
+ return;
+ }
+
+ vmime::string line = getNextLine();
+ std::istringstream iss(line);
+
+ switch (m_state) {
+
+ case STATE_NOT_CONNECTED:
+
+ localSend("451 Requested action aborted: invalid state\r\n");
+ break;
+
+ case STATE_COMMAND: {
+
+ std::string cmd;
+ iss >> cmd;
+
+ if (cmd.empty()) {
+
+ localSend("500 Syntax error, command unrecognized\r\n");
+
+ } else if (cmd == "EHLO") {
+
+ if (SUPPORTS_UTF8) {
+
+ localSend("250-test.vmime.org\r\n");
+ localSend("250 SMTPUTF8\r\n");
+
+ } else {
+
+ localSend("250 test.vmime.org\r\n");
+ }
+
+ m_ehloSent = true;
+
+ } else if (cmd == "HELO") {
+
+ VASSERT("Client must not send the HELO command, as EHLO succeeded", false);
+
+ } else if (cmd == "MAIL") {
+
+ VASSERT("Client must send the EHLO command", m_ehloSent);
+ VASSERT("The MAIL command must be sent only one time", !m_mailSent);
+
+ if (SUPPORTS_UTF8) {
+
+ VASSERT(
+ "MAIL",
+ std::string("MAIL FROM:<expediteur@test.vmime.org> SMTPUTF8") == line
+ || std::string("MAIL FROM:<expéditeur@test.vmime.org> SMTPUTF8") == line
+ );
+
+ } else {
+
+ VASSERT(
+ "MAIL",
+ std::string("MAIL FROM:<expediteur@test.vmime.org>") == line
+ || std::string("MAIL FROM:<=?utf-8?Q?exp=C3=A9diteur?=@test.vmime.org>") == line
+ );
+ }
+
+ localSend("250 OK\r\n");
+
+ m_mailSent = true;
+
+ } else if (cmd == "RCPT") {
+
+ std::set <vmime::string>::iterator it = m_rcptLines.find(line);
+
+ VASSERT(std::string("RCPT not found: '") + line + "'", it != m_rcptLines.end());
+
+ m_rcptLines.erase(it);
+
+ localSend("250 OK, recipient accepted\r\n");
+
+ m_rcptSent = true;
+
+ } else if (cmd == "DATA") {
+
+ VASSERT("Client must send the MAIL command", m_mailSent);
+ VASSERT("Client must send the RCPT command", m_rcptSent);
+ VASSERT("All recipients", m_rcptLines.empty());
+
+ localSend("354 Ready to accept data; end with <CRLF>.<CRLF>\r\n");
+
+ m_state = STATE_DATA;
+ m_msgData.clear();
+
+ m_dataSent = true;
+
+ } else if (cmd == "NOOP") {
+
+ localSend("250 Completed\r\n");
+
+ } else if (cmd == "QUIT") {
+
+ m_quitSent = true;
+
+ localSend("221 test.vmime.org Service closing transmission channel\r\n");
+
+ } else {
+
+ localSend("502 Command not implemented\r\n");
+ }
+
+ break;
+ }
+ case STATE_DATA: {
+
+ if (line == ".") {
+
+ VASSERT_EQ("Data", "Message data\r\n", m_msgData);
+
+ localSend("250 Message accepted for delivery\r\n");
+ m_state = STATE_COMMAND;
+
+ } else {
+
+ m_msgData += line + "\r\n";
+ }
+
+ break;
+ }
+
+ }
+
+ processCommand();
+ }
+
+private:
+
+ enum State {
+ STATE_NOT_CONNECTED,
+ STATE_COMMAND,
+ STATE_DATA
+ };
+
+ int m_state;
+
+ std::set <vmime::string> m_rcptLines;
+
+ std::string m_msgData;
+
+ bool m_ehloSent, m_mailSent, m_rcptSent, m_dataSent, m_quitSent;
+};
diff --git a/vmime-master/tests/parser/attachmentHelperTest.cpp b/vmime-master/tests/parser/attachmentHelperTest.cpp
new file mode 100644
index 0000000..866f8de
--- /dev/null
+++ b/vmime-master/tests/parser/attachmentHelperTest.cpp
@@ -0,0 +1,335 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "tests/testUtils.hpp"
+
+
+VMIME_TEST_SUITE_BEGIN(attachmentHelperTest)
+
+ VMIME_TEST_LIST_BEGIN
+ VMIME_TEST(testAddAttachment1)
+ VMIME_TEST(testAddAttachment2)
+ VMIME_TEST(testAddAttachment3)
+ VMIME_TEST(testIsBodyPartAnAttachment1)
+ VMIME_TEST(testIsBodyPartAnAttachment2)
+ VMIME_TEST(testIsBodyPartAnAttachment3)
+ VMIME_TEST(testGetBodyPartAttachment)
+ VMIME_TEST(testAddAttachmentMessage1)
+ VMIME_TEST(testGetBodyPartAttachmentMessage)
+ VMIME_TEST_LIST_END
+
+
+ static const vmime::string getStructure(const vmime::shared_ptr <vmime::bodyPart>& part) {
+
+ vmime::shared_ptr <vmime::body> bdy = part->getBody();
+
+ vmime::string res = part->getBody()->getContentType().generate();
+
+ if (bdy->getPartCount() == 0) {
+ return res;
+ }
+
+ res += "[";
+
+ for (size_t i = 0 ; i < bdy->getPartCount() ; ++i) {
+
+ vmime::shared_ptr <vmime::bodyPart> subPart = bdy->getPartAt(i);
+
+ if (i != 0) {
+ res += ",";
+ }
+
+ res += getStructure(subPart);
+ }
+
+ return res + "]";
+ }
+
+ static const vmime::string extractBodyContents(
+ const vmime::shared_ptr <const vmime::bodyPart>& part
+ ) {
+
+ vmime::shared_ptr <const vmime::contentHandler> cth = part->getBody()->getContents();
+
+ vmime::string data;
+ vmime::utility::outputStreamStringAdapter os(data);
+
+ cth->extract(os);
+
+ return data;
+ }
+
+ void testAddAttachment1() {
+
+ vmime::string data =
+"Content-Type: text/plain\r\n"
+"\r\n"
+"The text\r\n"
+"";
+
+ vmime::shared_ptr <vmime::message> msg = vmime::make_shared <vmime::message>();
+ msg->parse(data);
+
+ vmime::shared_ptr <vmime::attachment> att =
+ vmime::make_shared <vmime::defaultAttachment>(
+ vmime::make_shared <vmime::stringContentHandler>("test"),
+ vmime::mediaType("image/jpeg")
+ );
+
+ vmime::attachmentHelper::addAttachment(msg, att);
+
+ VASSERT_EQ("1", "multipart/mixed[text/plain,image/jpeg]", getStructure(msg));
+ VASSERT_EQ("2", "The text\r\n", extractBodyContents(msg->getBody()->getPartAt(0)));
+ }
+
+ void testAddAttachment2() {
+
+ vmime::string data =
+"Content-Type: multipart/mixed; boundary=\"foo\"\r\n"
+"\r\n"
+"--foo\r\n"
+"Content-Type: text/plain\r\n"
+"\r\n"
+"The text\r\n"
+"--foo\r\n"
+"Content-Type: application/octet-stream\r\n"
+"\r\n"
+"Blah\r\n"
+"--foo--\r\n"
+"";
+
+ vmime::shared_ptr <vmime::message> msg = vmime::make_shared <vmime::message>();
+ msg->parse(data);
+
+ vmime::shared_ptr <vmime::attachment> att =
+ vmime::make_shared <vmime::defaultAttachment>(
+ vmime::make_shared <vmime::stringContentHandler>("test"),
+ vmime::mediaType("image/jpeg")
+ );
+
+ vmime::attachmentHelper::addAttachment(msg, att);
+
+ VASSERT_EQ("1", "multipart/mixed[text/plain,application/octet-stream,image/jpeg]", getStructure(msg));
+ VASSERT_EQ("2", "The text", extractBodyContents(msg->getBody()->getPartAt(0)));
+ VASSERT_EQ("3", "Blah", extractBodyContents(msg->getBody()->getPartAt(1)));
+ VASSERT_EQ("4", "test", extractBodyContents(msg->getBody()->getPartAt(2)));
+ }
+
+ // Initial part is encoded
+ void testAddAttachment3() {
+
+ vmime::string data =
+"Content-Type: text/plain\r\n"
+"Content-Transfer-Encoding: base64\r\n"
+"\r\n"
+"TWVzc2FnZSBib2R5";
+
+ vmime::shared_ptr <vmime::message> msg = vmime::make_shared <vmime::message>();
+ msg->parse(data);
+
+ vmime::shared_ptr <vmime::attachment> att =
+ vmime::make_shared <vmime::defaultAttachment>(
+ vmime::make_shared <vmime::stringContentHandler>("test"),
+ vmime::mediaType("image/jpeg")
+ );
+
+ vmime::attachmentHelper::addAttachment(msg, att);
+
+ VASSERT_EQ("1", "multipart/mixed[text/plain,image/jpeg]", getStructure(msg));
+ VASSERT_EQ("2", "Message body", extractBodyContents(msg->getBody()->getPartAt(0)));
+ }
+
+ // Content-Disposition: attachment
+ // No other field
+ void testIsBodyPartAnAttachment1() {
+
+ vmime::string data = "Content-Disposition: attachment\r\n\r\nFoo\r\n";
+
+ vmime::shared_ptr <vmime::bodyPart> p = vmime::make_shared <vmime::bodyPart>();
+ p->parse(data);
+
+ VASSERT_EQ("1", true, vmime::attachmentHelper::isBodyPartAnAttachment(p));
+ }
+
+ // No Content-Disposition field
+ // Content-Type: multipart/* or text/*
+ void testIsBodyPartAnAttachment2() {
+
+ vmime::string data = "Content-Type: multipart/*\r\n\r\nFoo\r\n";
+
+ vmime::shared_ptr <vmime::bodyPart> p = vmime::make_shared <vmime::bodyPart>();
+ p->parse(data);
+
+ VASSERT_EQ("1", false, vmime::attachmentHelper::isBodyPartAnAttachment(p));
+
+ data = "Content-Type: text/*\r\n\r\nFoo\r\n";
+
+ p->parse(data);
+
+ VASSERT_EQ("2", false, vmime::attachmentHelper::isBodyPartAnAttachment(p));
+ }
+
+ // No Content-Disposition field
+ void testIsBodyPartAnAttachment3() {
+
+ vmime::string data = "Content-Type: application/octet-stream\r\n\r\nFoo\r\n";
+
+ vmime::shared_ptr <vmime::bodyPart> p = vmime::make_shared <vmime::bodyPart>();
+ p->parse(data);
+
+ VASSERT_EQ("1", true, vmime::attachmentHelper::isBodyPartAnAttachment(p));
+ }
+
+ // Content-Disposition: attachment
+ // Content-Id field present
+ void testIsBodyPartAnAttachment4() {
+
+ vmime::string data = "Content-Disposition: attachment\r\n"
+ "Content-Type: application/octet-stream\r\n"
+ "Content-Id: bar\r\n"
+ "\r\nFoo\r\n";
+
+ vmime::shared_ptr <vmime::bodyPart> p = vmime::make_shared <vmime::bodyPart>();
+ p->parse(data);
+
+ VASSERT_EQ("1", false, vmime::attachmentHelper::isBodyPartAnAttachment(p));
+ }
+
+ void testGetBodyPartAttachment() {
+
+ vmime::string data =
+ "Content-Type: image/jpeg\r\n"
+ "Content-Description: foobar\r\n"
+ "Content-Transfer-Encoding: x-baz\r\n"
+ "Content-Disposition: attachment; filename=\"foobar.baz\"\r\n"
+ "\r\n"
+ "Foo bar baz";
+
+ vmime::shared_ptr <vmime::bodyPart> part = vmime::make_shared <vmime::bodyPart>();
+ part->parse(data);
+
+ vmime::shared_ptr <const vmime::attachment> att =
+ vmime::attachmentHelper::getBodyPartAttachment(part);
+
+ VASSERT_EQ("1", "image/jpeg", att->getType().generate());
+ VASSERT_EQ("2", "foobar", att->getDescription().generate());
+ VASSERT_EQ("3", "x-baz", att->getEncoding().generate());
+ VASSERT_EQ("4", "foobar.baz", att->getName().generate());
+
+ vmime::string attData;
+ vmime::utility::outputStreamStringAdapter out(attData);
+ att->getData()->extractRaw(out); // 'x-baz' encoding not supported
+
+ VASSERT_EQ("5", "Foo bar baz", attData);
+
+ //VASSERT_EQ("6", part, att->getPart());
+ VASSERT_EQ("6", part->generate(), vmime::dynamicCast <const vmime::component>(att->getPart())->generate());
+ //VASSERT_EQ("7", part->getHeader(), att->getHeader());
+ VASSERT_EQ("7", part->getHeader()->generate(), att->getHeader()->generate());
+ }
+
+ void testAddAttachmentMessage1() {
+
+ const vmime::string data =
+"Subject: Test message\r\n"
+"Content-Type: text/plain\r\n"
+"\r\n"
+"Message body";
+
+ vmime::shared_ptr <vmime::message> msg = vmime::make_shared <vmime::message>();
+ msg->parse(data);
+
+ const vmime::string attData =
+"Subject: Attached message\r\n"
+"Content-Type: text/plain\r\n"
+"Content-Transfer-Encoding: base64\r\n"
+"\r\n"
+"QXR0YWNoZWQgbWVzc2FnZSBib2R5";
+
+ vmime::shared_ptr <vmime::message> amsg = vmime::make_shared <vmime::message>();
+ amsg->parse(attData);
+
+ vmime::attachmentHelper::addAttachment(msg, amsg);
+
+ VASSERT_EQ("1", "multipart/mixed[text/plain,message/rfc822]", getStructure(msg));
+ VASSERT_EQ("2", "Message body", extractBodyContents(msg->getBody()->getPartAt(0)));
+
+ // Ensure message has been encoded properly
+ vmime::shared_ptr <const vmime::bodyPart> attPart = msg->getBody()->getPartAt(1);
+ vmime::shared_ptr <const vmime::contentHandler> attCth = attPart->getBody()->getContents();
+
+ vmime::string attDataOut;
+ vmime::utility::outputStreamStringAdapter attDataOutOs(attDataOut);
+
+ attCth->extract(attDataOutOs);
+
+ vmime::shared_ptr <vmime::message> amsgOut = vmime::make_shared <vmime::message>();
+ amsgOut->parse(attDataOut);
+
+ vmime::shared_ptr <vmime::header> hdr = amsgOut->getHeader();
+
+ VASSERT_EQ("3", "Attached message", hdr->Subject()->getValue <vmime::text>()->generate());
+ VASSERT_EQ("4", "Attached message body", extractBodyContents(amsgOut));
+ }
+
+ void testGetBodyPartAttachmentMessage() {
+
+ const vmime::string data =
+"Subject: Test message\r\n"
+"Content-Type: multipart/mixed; boundary=\"foo\"\r\n"
+"\r\n"
+"--foo\r\n"
+"Content-Type: message/rfc822\r\n"
+"\r\n"
+"Subject: Attached message\r\n"
+"\r\n"
+"Attached message body\r\n"
+"--foo\r\n"
+"Content-Type: text/plain\r\n"
+"\r\n"
+"FooBar\r\n"
+"--foo--\r\n";
+
+ vmime::shared_ptr <vmime::message> msg = vmime::make_shared <vmime::message>();
+ msg->parse(data);
+
+ VASSERT_EQ("0", 2, msg->getBody()->getPartCount());
+
+ vmime::shared_ptr <const vmime::attachment> att =
+ vmime::attachmentHelper::getBodyPartAttachment(msg->getBody()->getPartAt(0));
+
+ VASSERT("1", att != NULL);
+
+ vmime::shared_ptr <const vmime::messageAttachment> msgAtt =
+ vmime::dynamicCast <const vmime::messageAttachment>(att);
+
+ VASSERT("2", msgAtt != NULL);
+
+ vmime::shared_ptr <vmime::message> amsg = msgAtt->getMessage();
+ vmime::shared_ptr <vmime::header> hdr = amsg->getHeader();
+
+ VASSERT_EQ("3", "Attached message", hdr->Subject()->getValue <vmime::text>()->generate());
+ VASSERT_EQ("4", "Attached message body", extractBodyContents(amsg));
+ }
+
+VMIME_TEST_SUITE_END
diff --git a/vmime-master/tests/parser/bodyPartTest.cpp b/vmime-master/tests/parser/bodyPartTest.cpp
new file mode 100644
index 0000000..3aaadd0
--- /dev/null
+++ b/vmime-master/tests/parser/bodyPartTest.cpp
@@ -0,0 +1,414 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "tests/testUtils.hpp"
+
+
+VMIME_TEST_SUITE_BEGIN(bodyPartTest)
+
+ VMIME_TEST_LIST_BEGIN
+ VMIME_TEST(testParse)
+ VMIME_TEST(testGenerate)
+ VMIME_TEST(testParseGuessBoundary)
+ VMIME_TEST(testParseGuessBoundaryWithTransportPadding)
+ VMIME_TEST(testParseMissingLastBoundary)
+ VMIME_TEST(testPrologEpilog)
+ VMIME_TEST(testPrologEncoding)
+ VMIME_TEST(testSuccessiveBoundaries)
+ VMIME_TEST(testTransportPaddingInBoundary)
+ VMIME_TEST(testGenerate7bit)
+ VMIME_TEST(testTextUsageForQPEncoding)
+ VMIME_TEST(testParseVeryBigMessage)
+ VMIME_TEST(testParseBoundaryPrefix)
+ VMIME_TEST_LIST_END
+
+
+ static const vmime::string extractComponentString(
+ const vmime::string& buffer,
+ const vmime::component& c
+ ) {
+
+ return vmime::string(
+ buffer.begin() + c.getParsedOffset(),
+ buffer.begin() + c.getParsedOffset() + c.getParsedLength()
+ );
+ }
+
+ static const vmime::string extractContents(
+ const vmime::shared_ptr <const vmime::contentHandler>& cts
+ ) {
+
+ std::ostringstream oss;
+ vmime::utility::outputStreamAdapter os(oss);
+
+ cts->extract(os);
+
+ return oss.str();
+ }
+
+
+ void testParse() {
+
+ vmime::string str1 = "HEADER\r\n\r\nBODY";
+ vmime::bodyPart p1;
+ p1.parse(str1);
+
+ VASSERT_EQ("1", "HEADER\r\n\r\n", extractComponentString(str1, *p1.getHeader()));
+ VASSERT_EQ("2", "BODY", extractComponentString(str1, *p1.getBody()));
+
+ vmime::string str2 = "HEADER\n\nBODY";
+ vmime::bodyPart p2;
+ p2.parse(str2);
+
+ VASSERT_EQ("3", "HEADER\n\n", extractComponentString(str2, *p2.getHeader()));
+ VASSERT_EQ("4", "BODY", extractComponentString(str2, *p2.getBody()));
+
+ vmime::string str3 = "HEADER\r\n\nBODY";
+ vmime::bodyPart p3;
+ p3.parse(str3);
+
+ VASSERT_EQ("5", "HEADER\r\n\n", extractComponentString(str3, *p3.getHeader()));
+ VASSERT_EQ("6", "BODY", extractComponentString(str3, *p3.getBody()));
+ }
+
+ void testParseMissingLastBoundary() {
+
+ vmime::string str =
+ "Content-Type: multipart/mixed; boundary=\"MY-BOUNDARY\""
+ "\r\n\r\n"
+ "--MY-BOUNDARY\r\nHEADER1\r\n\r\nBODY1\r\n"
+ "--MY-BOUNDARY\r\nHEADER2\r\n\r\nBODY2";
+
+ vmime::bodyPart p;
+ p.parse(str);
+
+ VASSERT_EQ("count", 2, p.getBody()->getPartCount());
+
+ VASSERT_EQ("part1-body", "BODY1", extractContents(p.getBody()->getPartAt(0)->getBody()->getContents()));
+ VASSERT_EQ("part2-body", "BODY2", extractContents(p.getBody()->getPartAt(1)->getBody()->getContents()));
+ }
+
+ void testGenerate() {
+
+ vmime::bodyPart p1;
+ p1.getHeader()->getField("Foo")->setValue(vmime::string("bar"));
+ p1.getBody()->setContents(vmime::make_shared <vmime::stringContentHandler>("Baz"));
+
+ VASSERT_EQ("1", "Foo: bar\r\n\r\nBaz", p1.generate());
+ }
+
+ void testPrologEpilog() {
+
+ const char testMail[] =
+ "To: test@vmime.org\r\n"
+ "From: test@vmime.org\r\n"
+ "Subject: Prolog and epilog test\r\n"
+ "Content-Type: multipart/mixed; \r\n"
+ " boundary=\"=_boundary\"\r\n"
+ "\r\n"
+ "Prolog text\r\n"
+ "--=_boundary\r\n"
+ "Content-Type: text/plain\r\n"
+ "\r\n"
+ "Part1\r\n"
+ "--=_boundary--\r\n"
+ "Epilog text";
+
+ vmime::bodyPart part;
+ part.parse(testMail);
+
+ VASSERT_EQ("prolog", "Prolog text", part.getBody()->getPrologText());
+ VASSERT_EQ("epilog", "Epilog text", part.getBody()->getEpilogText());
+ }
+
+ // Test for bug fix: prolog should not be encoded
+ // http://sourceforge.net/tracker/?func=detail&atid=525568&aid=3174903&group_id=69724
+ void testPrologEncoding() {
+
+ const char testmail[] =
+ "To: test@vmime.org\r\n"
+ "From: test@vmime.org\r\n"
+ "Subject: Prolog encoding test\r\n"
+ "Content-Type: multipart/mixed; \r\n"
+ " boundary=\"=_+ZWjySayKqSf2CyrfnNpaAcO6-G1HpoXdHZ4YyswAWqEY39Q\"\r\n"
+ "\r\n"
+ "This is a multi-part message in MIME format. Your mail reader does not\r\n"
+ "understand MIME message format.\r\n"
+ "--=_+ZWjySayKqSf2CyrfnNpaAcO6-G1HpoXdHZ4YyswAWqEY39Q\r\n"
+ "Content-Type: text/html; charset=windows-1251\r\n"
+ "Content-Transfer-Encoding: quoted-printable\r\n"
+ "\r\n"
+ "=DD=F2=EE =F2=E5=EA=F1=F2=EE=E2=E0=FF =F7=E0=F1=F2=FC =F1=EB=EE=E6=ED=EE=E3=\r\n"
+ "=EE =F1=EE=EE=E1=F9=E5=ED=E8=FF\r\n"
+ "--=_+ZWjySayKqSf2CyrfnNpaAcO6-G1HpoXdHZ4YyswAWqEY39Q\r\n"
+ "Content-Type: application/octet-stream; charset=windows-1251\r\n"
+ "Content-Disposition: attachment; filename=FNS.zip\r\n"
+ "Content-Transfer-Encoding: base64\r\n"
+ "\r\n"
+ "UEsDBB...snap...EEAAAAAA==\r\n"
+ "--=_+ZWjySayKqSf2CyrfnNpaAcO6-G1HpoXdHZ4YyswAWqEY39Q--\r\n"
+ "Epilog text";
+
+ vmime::shared_ptr<vmime::message> msg = vmime::make_shared<vmime::message>();
+
+ std::string istr(testmail);
+
+ std::string ostr;
+ vmime::utility::outputStreamStringAdapter out(ostr);
+
+ for (int i = 0 ; i < 10 ; ++i) {
+
+ ostr.clear();
+
+ msg->parse(istr);
+ msg->generate(out);
+
+ istr = ostr;
+ }
+
+ VASSERT_EQ("prolog", "This is a multi-part message in MIME format. Your mail reader"
+ " does not understand MIME message format.", msg->getBody()->getPrologText());
+ VASSERT_EQ("epilog", "Epilog text", msg->getBody()->getEpilogText());
+ }
+
+ void testSuccessiveBoundaries() {
+
+ vmime::string str =
+ "Content-Type: multipart/mixed; boundary=\"MY-BOUNDARY\""
+ "\r\n\r\n"
+ "--MY-BOUNDARY\r\nHEADER1\r\n\r\nBODY1\r\n"
+ "--MY-BOUNDARY\r\n"
+ "--MY-BOUNDARY--\r\n";
+
+ vmime::bodyPart p;
+ p.parse(str);
+
+ VASSERT_EQ("count", 2, p.getBody()->getPartCount());
+
+ VASSERT_EQ("part1-body", "BODY1", extractContents(p.getBody()->getPartAt(0)->getBody()->getContents()));
+ VASSERT_EQ("part2-body", "", extractContents(p.getBody()->getPartAt(1)->getBody()->getContents()));
+ }
+
+ void testTransportPaddingInBoundary() {
+
+ vmime::string str =
+ "Content-Type: multipart/mixed; boundary=\"MY-BOUNDARY\""
+ "\r\n\r\n"
+ "--MY-BOUNDARY \t \r\nHEADER1\r\n\r\nBODY1\r\n"
+ "--MY-BOUNDARY\r\n"
+ "--MY-BOUNDARY-- \r\n";
+
+ vmime::bodyPart p;
+ p.parse(str);
+
+ VASSERT_EQ("count", 2, p.getBody()->getPartCount());
+
+ VASSERT_EQ("part1-body", "BODY1", extractContents(p.getBody()->getPartAt(0)->getBody()->getContents()));
+ VASSERT_EQ("part2-body", "", extractContents(p.getBody()->getPartAt(1)->getBody()->getContents()));
+ }
+
+ /** Ensure '7bit' encoding is used when body is 7-bit only. */
+ void testGenerate7bit() {
+
+ vmime::shared_ptr <vmime::plainTextPart> p1 = vmime::make_shared <vmime::plainTextPart>();
+ p1->setText(vmime::make_shared <vmime::stringContentHandler>("Part1 is US-ASCII only."));
+
+ vmime::shared_ptr <vmime::message> msg = vmime::make_shared <vmime::message>();
+ p1->generateIn(msg, msg);
+
+ vmime::shared_ptr <vmime::header> header1 = msg->getBody()->getPartAt(0)->getHeader();
+ VASSERT_EQ("1", "7bit", header1->ContentTransferEncoding()->getValue()->generate());
+ }
+
+ void testTextUsageForQPEncoding() {
+
+ vmime::shared_ptr <vmime::plainTextPart> part = vmime::make_shared <vmime::plainTextPart>();
+ part->setText(vmime::make_shared <vmime::stringContentHandler>("Part1-line1\r\nPart1-line2\r\n\x89"));
+
+ vmime::shared_ptr <vmime::message> msg = vmime::make_shared <vmime::message>();
+ part->generateIn(msg, msg);
+
+ vmime::shared_ptr <vmime::body> body = msg->getBody()->getPartAt(0)->getBody();
+ vmime::shared_ptr <vmime::header> header = msg->getBody()->getPartAt(0)->getHeader();
+
+ std::ostringstream oss;
+ vmime::utility::outputStreamAdapter os(oss);
+ body->generate(os, 80);
+
+ VASSERT_EQ("1", "quoted-printable", header->ContentTransferEncoding()->getValue()->generate());
+
+ // This should *NOT* be:
+ // Part1-line1=0D=0APart1-line2=0D=0A=89
+ VASSERT_EQ("2", "Part1-line1\r\nPart1-line2\r\n=89", oss.str());
+ }
+
+ void testParseGuessBoundary() {
+
+ // Boundary is not specified in "Content-Type" field
+ // Parser will try to guess it from message contents.
+
+ vmime::string str =
+ "Content-Type: multipart/mixed"
+ "\r\n\r\n"
+ "--UNKNOWN-BOUNDARY\r\nHEADER1\r\n\r\nBODY1\r\n"
+ "--UNKNOWN-BOUNDARY\r\nHEADER2\r\n\r\nBODY2\r\n"
+ "--UNKNOWN-BOUNDARY--";
+
+ vmime::bodyPart p;
+ p.parse(str);
+
+ VASSERT_EQ("count", 2, p.getBody()->getPartCount());
+
+ VASSERT_EQ("part1-body", "BODY1", extractContents(p.getBody()->getPartAt(0)->getBody()->getContents()));
+ VASSERT_EQ("part2-body", "BODY2", extractContents(p.getBody()->getPartAt(1)->getBody()->getContents()));
+ }
+
+ void testParseGuessBoundaryWithTransportPadding() {
+
+ // Boundary is not specified in "Content-Type" field
+ // Parser will try to guess it from message contents.
+ // Transport padding white spaces should be ignored.
+
+ vmime::string str =
+ "Content-Type: multipart/mixed"
+ "\r\n\r\n"
+ "--UNKNOWN-BOUNDARY \t \r\nHEADER1\r\n\r\nBODY1\r\n"
+ "--UNKNOWN-BOUNDARY\r\nHEADER2\r\n\r\nBODY2\r\n"
+ "--UNKNOWN-BOUNDARY--";
+
+ vmime::bodyPart p;
+ p.parse(str);
+
+ VASSERT_EQ("count", 2, p.getBody()->getPartCount());
+
+ VASSERT_EQ("part1-body", "BODY1", extractContents(p.getBody()->getPartAt(0)->getBody()->getContents()));
+ VASSERT_EQ("part2-body", "BODY2", extractContents(p.getBody()->getPartAt(1)->getBody()->getContents()));
+ }
+
+ void testParseVeryBigMessage() {
+
+ // When parsing from a seekable input stream, body contents should not
+ // be kept in memory in a "stringContentHandler" object. Instead, content
+ // should be accessible via a "streamContentHandler" object.
+
+ static const std::string BODY1_BEGIN = "BEGIN1BEGIN1BEGIN1";
+ static const std::string BODY1_LINE = "BODY1BODY1BODY1BODY1BODY1BODY1BODY1BODY1BODY1BODY1BODY1BODY1BODY1";
+ static const std::string BODY1_END = "END1END1";
+ static const unsigned int BODY1_REPEAT = 35000;
+ static const size_t BODY1_LENGTH =
+ BODY1_BEGIN.length() + BODY1_LINE.length() * BODY1_REPEAT + BODY1_END.length();
+
+ static const std::string BODY2_LINE = "BODY2BODY2BODY2BODY2BODY2BODY2BODY2BODY2BODY2BODY2BODY2BODY2BODY2";
+ static const unsigned int BODY2_REPEAT = 20000;
+
+ std::ostringstream oss;
+ oss << "Content-Type: multipart/mixed; boundary=\"MY-BOUNDARY\""
+ << "\r\n\r\n"
+ << "--MY-BOUNDARY\r\n"
+ << "HEADER1\r\n"
+ << "\r\n";
+
+ oss << BODY1_BEGIN;
+
+ for (unsigned int i = 0 ; i < BODY1_REPEAT ; ++i) {
+ oss << BODY1_LINE;
+ }
+
+ oss << BODY1_END;
+
+ oss << "\r\n"
+ << "--MY-BOUNDARY\r\n"
+ << "HEADER2\r\n"
+ << "\r\n";
+
+ for (unsigned int i = 0 ; i < BODY2_REPEAT ; ++i) {
+ oss << BODY2_LINE;
+ }
+
+ oss << "\r\n"
+ << "--MY-BOUNDARY--\r\n";
+
+ vmime::shared_ptr <vmime::utility::inputStreamStringAdapter> is =
+ vmime::make_shared <vmime::utility::inputStreamStringAdapter>(oss.str());
+
+ vmime::shared_ptr <vmime::message> msg = vmime::make_shared <vmime::message>();
+ msg->parse(is, oss.str().length());
+
+ vmime::shared_ptr <vmime::body> body1 = msg->getBody()->getPartAt(0)->getBody();
+ vmime::shared_ptr <const vmime::contentHandler> body1Cts = body1->getContents();
+
+ vmime::shared_ptr <vmime::body> body2 = msg->getBody()->getPartAt(1)->getBody();
+ vmime::shared_ptr <const vmime::contentHandler> body2Cts = body2->getContents();
+
+ vmime::string body1CtsExtracted;
+ vmime::utility::outputStreamStringAdapter body1CtsExtractStream(body1CtsExtracted);
+ body1Cts->extract(body1CtsExtractStream);
+
+ VASSERT_EQ("1.1", BODY1_LENGTH, body1Cts->getLength());
+ VASSERT("1.2", vmime::dynamicCast <const vmime::streamContentHandler>(body1Cts) != NULL);
+ VASSERT_EQ("1.3", BODY1_LENGTH, body1CtsExtracted.length());
+ VASSERT_EQ("1.4", BODY1_BEGIN, body1CtsExtracted.substr(0, BODY1_BEGIN.length()));
+ VASSERT_EQ("1.5", BODY1_END, body1CtsExtracted.substr(BODY1_LENGTH - BODY1_END.length(), BODY1_END.length()));
+
+ VASSERT_EQ("2.1", BODY2_LINE.length() * BODY2_REPEAT, body2Cts->getLength());
+ VASSERT("2.2", vmime::dynamicCast <const vmime::streamContentHandler>(body2Cts) != NULL);
+ }
+
+ void testParseBoundaryPrefix() {
+ /*
+ * Clients are not supposed to create boundary identifiers that
+ * contain a prefix of another (RFC 2046 section 5.1), but alas
+ * CANCOM FortiMail produces this garbage.
+ */
+ vmime::string str =
+ "Content-Type: multipart/related; boundary=\"--b12\"\r\n"
+ "\r\n"
+ "----b12\r\n"
+ "Content-Type: multipart/alternative; boundary=\"--b12-1\"\r\n"
+ "\r\n"
+ "----b12-1\r\n"
+ "Content-Type: text/plain; charset=utf-8\r\n"
+ "\r\n"
+ "P11\r\n"
+ "----b12-1\r\n"
+ "Content-Type: text/html; charset=utf-8\r\n"
+ "\r\n"
+ "P12\r\n"
+ "----b12-1--\r\n"
+ "----b12\r\n"
+ "\r\n"
+ "P2\r\n"
+ "----b12--\r\n";
+
+ vmime::bodyPart relco;
+ relco.parse(str);
+ auto relbd = relco.getBody();
+ VASSERT_EQ("global-partcount", 2, relbd->getPartCount());
+ auto altbd = relbd->getPartAt(0)->getBody();
+ VASSERT_EQ("part1-partcount", 2, altbd->getPartCount());
+ VASSERT_EQ("part1.1-body", "P11", extractContents(altbd->getPartAt(0)->getBody()->getContents()));
+ VASSERT_EQ("part1.2-body", "P12", extractContents(altbd->getPartAt(1)->getBody()->getContents()));
+ VASSERT_EQ("part2-body", "P2", extractContents(relbd->getPartAt(1)->getBody()->getContents()));
+ }
+
+VMIME_TEST_SUITE_END
diff --git a/vmime-master/tests/parser/bodyTest.cpp b/vmime-master/tests/parser/bodyTest.cpp
new file mode 100644
index 0000000..31054f3
--- /dev/null
+++ b/vmime-master/tests/parser/bodyTest.cpp
@@ -0,0 +1,79 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "tests/testUtils.hpp"
+
+
+VMIME_TEST_SUITE_BEGIN(bodyTest)
+
+ VMIME_TEST_LIST_BEGIN
+ VMIME_TEST(testGenerate_Text)
+ VMIME_TEST(testGenerate_NonText)
+ VMIME_TEST_LIST_END
+
+ void testGenerate_Text() {
+
+ // RFC-2015: [Quoted-Printable encoding] A line break in a text body,
+ // represented as a CRLF sequence in the text canonical form, must be
+ // represented by a line break which is also a CRLF sequence, in the
+ // Quoted-Printable encoding
+
+ vmime::bodyPart p;
+ p.getBody()->setContents(
+ vmime::make_shared <vmime::stringContentHandler>(
+ "Foo éé\r\né bar\r\nbaz"
+ ),
+ vmime::mediaType("text", "plain"),
+ vmime::charset("utf-8"),
+ vmime::encoding("quoted-printable")
+ );
+
+ VASSERT_EQ(
+ "generate",
+ "Foo =C3=A9=C3=A9\r\n"
+ "=C3=A9 bar\r\n"
+ "baz",
+ p.getBody()->generate()
+ );
+ }
+
+ void testGenerate_NonText() {
+
+ vmime::bodyPart p;
+ p.getBody()->setContents(
+ vmime::make_shared <vmime::stringContentHandler>(
+ "Binary\xfa\xfb\r\ndata\r\n\r\n\xfc"
+ ),
+ vmime::mediaType("application", "octet-stream"),
+ vmime::charset("utf-8"),
+ vmime::encoding("quoted-printable")
+ );
+
+ VASSERT_EQ(
+ "generate",
+ "Binary=FA=FB=0D=0Adata=0D=0A=0D=0A=FC",
+ p.getBody()->generate()
+ );
+ }
+
+VMIME_TEST_SUITE_END
diff --git a/vmime-master/tests/parser/charsetFilteredOutputStreamTest.cpp b/vmime-master/tests/parser/charsetFilteredOutputStreamTest.cpp
new file mode 100644
index 0000000..0ebd83a
--- /dev/null
+++ b/vmime-master/tests/parser/charsetFilteredOutputStreamTest.cpp
@@ -0,0 +1,213 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "tests/testUtils.hpp"
+
+#include "vmime/charset.hpp"
+#include "vmime/charsetConverter.hpp"
+
+#include "charsetTestSuites.hpp"
+
+
+VMIME_TEST_SUITE_BEGIN(charsetFilteredOutputStreamTest)
+
+ VMIME_TEST_LIST_BEGIN
+ VMIME_TEST(testInputBufferUnderflow)
+ VMIME_TEST(testInvalidInput1)
+ VMIME_TEST(testStreamCopy)
+ VMIME_TEST(testOneByteAtTime)
+ VMIME_TEST(testVariableInputChunk)
+ VMIME_TEST_LIST_END
+
+
+ void testInputBufferUnderflow() {
+
+ vmime::shared_ptr <vmime::charsetConverter> cc =
+ vmime::charsetConverter::create("utf-8", "iso-8859-1");
+
+ vmime::string output;
+ vmime::utility::outputStreamStringAdapter os(output);
+ vmime::shared_ptr <vmime::utility::filteredOutputStream> cfos = cc->getFilteredOutputStream(os);
+
+ VASSERT_NOT_NULL("filteredOutputStream availability", cfos);
+
+ // føo = 66 c3 b8 6f [UTF8]
+ // føo = 66 f8 6f [latin1]
+
+ cfos->write("\x66\xc3", 2);
+
+ // Incomplete UTF-8 sequence was not converted
+ VASSERT_EQ("chunk 1", toHex("f"), toHex(output));
+
+ // Write second byte of UTF-8 sequence
+ cfos->write("\xb8\x6f", 2);
+
+ VASSERT_EQ("chunk 2", toHex("f\xf8o"), toHex(output));
+ }
+
+ void testInvalidInput1() {
+
+ vmime::string in("foo\xab\xcd\xef bar");
+ vmime::string expectedOut("foo??? bar");
+
+ vmime::string actualOut;
+ vmime::utility::outputStreamStringAdapter osa(actualOut);
+
+ vmime::shared_ptr <vmime::charsetConverter> conv =
+ vmime::charsetConverter::create(vmime::charset("utf-8"), vmime::charset("iso-8859-1"));
+
+ vmime::shared_ptr <vmime::utility::charsetFilteredOutputStream> os =
+ conv->getFilteredOutputStream(osa);
+
+ VASSERT_NOT_NULL("filteredOutputStream availability", os);
+
+ vmime::utility::inputStreamStringAdapter is(in);
+
+ vmime::byte_t buffer[16];
+
+ for (int i = 0 ; !is.eof() ; ++i)
+ os->write(buffer, is.read(buffer, 1));
+
+ os->flush();
+
+ VASSERT_EQ("1", toHex(expectedOut), toHex(actualOut));
+ }
+
+ // Using 'bufferedStreamCopy'
+ void testStreamCopy() {
+
+ for (unsigned int i = 0 ; i < charsetTestSuitesCount ; ++i) {
+
+ const charsetTestSuiteStruct& entry = charsetTestSuites[i];
+
+ std::ostringstream testName;
+ testName << i << ": " << entry.fromCharset << " -> " << entry.toCharset;
+
+ const unsigned long inLength = (entry.fromLength == 0 ? strlen(entry.fromBytes) : entry.fromLength);
+ vmime::string in(entry.fromBytes, entry.fromBytes + inLength);
+
+ const unsigned long outLength = (entry.toLength == 0 ? strlen(entry.toBytes) : entry.toLength);
+ vmime::string expectedOut(entry.toBytes, entry.toBytes + outLength);
+
+ vmime::string actualOut;
+ vmime::utility::outputStreamStringAdapter osa(actualOut);
+
+ vmime::shared_ptr <vmime::charsetConverter> conv =
+ vmime::charsetConverter::create(entry.fromCharset, entry.toCharset);
+
+ vmime::shared_ptr <vmime::utility::charsetFilteredOutputStream> os =
+ conv->getFilteredOutputStream(osa);
+
+ VASSERT_NOT_NULL("filteredOutputStream availability", os);
+
+ vmime::utility::inputStreamStringAdapter is(in);
+
+ vmime::utility::bufferedStreamCopy(is, *os);
+
+ os->flush();
+
+ VASSERT_EQ(testName.str(), toHex(expectedOut), toHex(actualOut));
+ }
+ }
+
+ // One byte at a time
+ void testOneByteAtTime() {
+
+ for (unsigned int i = 0 ; i < charsetTestSuitesCount ; ++i) {
+
+ const charsetTestSuiteStruct& entry = charsetTestSuites[i];
+
+ std::ostringstream testName;
+ testName << i << ": " << entry.fromCharset << " -> " << entry.toCharset;
+
+ const unsigned long inLength = (entry.fromLength == 0 ? strlen(entry.fromBytes) : entry.fromLength);
+ vmime::string in(entry.fromBytes, entry.fromBytes + inLength);
+
+ const unsigned long outLength = (entry.toLength == 0 ? strlen(entry.toBytes) : entry.toLength);
+ vmime::string expectedOut(entry.toBytes, entry.toBytes + outLength);
+
+ vmime::string actualOut;
+ vmime::utility::outputStreamStringAdapter osa(actualOut);
+
+ vmime::shared_ptr <vmime::charsetConverter> conv =
+ vmime::charsetConverter::create(entry.fromCharset, entry.toCharset);
+
+ vmime::shared_ptr <vmime::utility::charsetFilteredOutputStream> os =
+ conv->getFilteredOutputStream(osa);
+
+ VASSERT_NOT_NULL("filteredOutputStream availability", os);
+
+ vmime::utility::inputStreamStringAdapter is(in);
+
+ vmime::byte_t buffer[16];
+
+ for (int i = 0 ; !is.eof() ; ++i)
+ os->write(buffer, is.read(buffer, 1));
+
+ os->flush();
+
+ VASSERT_EQ(testName.str(), toHex(expectedOut), toHex(actualOut));
+ }
+ }
+
+ // Variable chunks
+ void testVariableInputChunk() {
+
+ for (unsigned int i = 0 ; i < charsetTestSuitesCount ; ++i) {
+
+ const charsetTestSuiteStruct& entry = charsetTestSuites[i];
+
+ std::ostringstream testName;
+ testName << i << ": " << entry.fromCharset << " -> " << entry.toCharset;
+
+ const unsigned long inLength = (entry.fromLength == 0 ? strlen(entry.fromBytes) : entry.fromLength);
+ vmime::string in(entry.fromBytes, entry.fromBytes + inLength);
+
+ const unsigned long outLength = (entry.toLength == 0 ? strlen(entry.toBytes) : entry.toLength);
+ vmime::string expectedOut(entry.toBytes, entry.toBytes + outLength);
+
+ vmime::string actualOut;
+ vmime::utility::outputStreamStringAdapter osa(actualOut);
+
+ vmime::shared_ptr <vmime::charsetConverter> conv =
+ vmime::charsetConverter::create(entry.fromCharset, entry.toCharset);
+
+ vmime::shared_ptr <vmime::utility::charsetFilteredOutputStream> os =
+ conv->getFilteredOutputStream(osa);
+
+ VASSERT_NOT_NULL("filteredOutputStream availability", os);
+
+ vmime::utility::inputStreamStringAdapter is(in);
+
+ vmime::byte_t buffer[16];
+
+ for (int i = 0 ; !is.eof() ; ++i)
+ os->write(buffer, is.read(buffer, (i % 5) + 1));
+
+ os->flush();
+
+ VASSERT_EQ(testName.str(), toHex(expectedOut), toHex(actualOut));
+ }
+ }
+
+VMIME_TEST_SUITE_END
diff --git a/vmime-master/tests/parser/charsetTest.cpp b/vmime-master/tests/parser/charsetTest.cpp
new file mode 100644
index 0000000..e44bef5
--- /dev/null
+++ b/vmime-master/tests/parser/charsetTest.cpp
@@ -0,0 +1,252 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include <algorithm>
+
+#include "tests/testUtils.hpp"
+
+#include "charsetTestSuites.hpp"
+
+
+VMIME_TEST_SUITE_BEGIN(charsetTest)
+
+ VMIME_TEST_LIST_BEGIN
+ // Test valid input
+ VMIME_TEST(testConvertStringValid)
+ VMIME_TEST(testConvertStreamValid)
+ VMIME_TEST(testEncodingHebrew1255)
+
+ // IDNA
+ VMIME_TEST(testEncodeIDNA)
+ VMIME_TEST(testDecodeIDNA)
+
+ VMIME_TEST(testUTF7Support)
+
+ VMIME_TEST(testReplaceInvalidSequence)
+ VMIME_TEST(testStopOnInvalidSequence)
+
+ VMIME_TEST(testStatus)
+ VMIME_TEST(testStatusWithInvalidSequence)
+
+ VMIME_TEST(testIsValidText)
+ VMIME_TEST_LIST_END
+
+
+ void testConvertStringValid() {
+
+ for (unsigned int i = 0 ; i < charsetTestSuitesCount ; ++i) {
+
+ const charsetTestSuiteStruct& entry = charsetTestSuites[i];
+
+ std::ostringstream testName;
+ testName << i << ": " << entry.fromCharset << " -> " << entry.toCharset;
+
+ const unsigned long inLength = (entry.fromLength == 0 ? strlen(entry.fromBytes) : entry.fromLength);
+ vmime::string in(entry.fromBytes, entry.fromBytes + inLength);
+
+ const unsigned long outLength = (entry.toLength == 0 ? strlen(entry.toBytes) : entry.toLength);
+ vmime::string expectedOut(entry.toBytes, entry.toBytes + outLength);
+
+ vmime::string actualOut;
+
+ vmime::charset::convert
+ (in, actualOut, entry.fromCharset, entry.toCharset);
+
+ VASSERT_EQ(testName.str(), toHex(expectedOut), toHex(actualOut));
+ }
+ }
+
+ void testConvertStreamValid() {
+
+ for (unsigned int i = 0 ; i < charsetTestSuitesCount ; ++i) {
+
+ const charsetTestSuiteStruct& entry = charsetTestSuites[i];
+
+ std::ostringstream testName;
+ testName << i << ": " << entry.fromCharset << " -> " << entry.toCharset;
+
+ const unsigned long inLength = (entry.fromLength == 0 ? strlen(entry.fromBytes) : entry.fromLength);
+ vmime::string in(entry.fromBytes, entry.fromBytes + inLength);
+
+ const unsigned long outLength = (entry.toLength == 0 ? strlen(entry.toBytes) : entry.toLength);
+ vmime::string expectedOut(entry.toBytes, entry.toBytes + outLength);
+
+ vmime::string actualOut;
+ vmime::utility::outputStreamStringAdapter os(actualOut);
+
+ vmime::utility::inputStreamStringAdapter is(in);
+
+ vmime::charset::convert(is, os, entry.fromCharset, entry.toCharset);
+
+ os.flush();
+
+ VASSERT_EQ(testName.str(), toHex(expectedOut), toHex(actualOut));
+ }
+ }
+
+ void testEncodingHebrew1255() {
+
+ // hewbrew string in windows-1255 charset
+ const char data[] = "\xe9\xf9\xf7\xf8\xe9\xf9\xf8\xf7\xe9\xe9\xf9";
+ vmime::word w = vmime::word(data, "windows-1255");
+ vmime::string encoded = w.generate();
+ // less than 60% ascii, base64 received
+ VASSERT_EQ("1", "=?windows-1255?B?6fn3+On5+Pfp6fk=?=", encoded);
+ }
+
+ static const vmime::string convertHelper(
+ const vmime::string& in,
+ const vmime::charset& csrc,
+ const vmime::charset& cdest,
+ const vmime::charsetConverterOptions& opts = vmime::charsetConverterOptions(),
+ vmime::charsetConverter::status* st = NULL
+ ) {
+
+ vmime::shared_ptr <vmime::charsetConverter> conv =
+ vmime::charsetConverter::create(csrc, cdest, opts);
+
+ vmime::string out;
+ conv->convert(in, out, st);
+
+ return out;
+ }
+
+ void testEncodeIDNA() {
+
+ VASSERT_EQ("1", "xn--espaol-zwa", convertHelper("español", "utf-8", "idna"));
+
+ // Tests from ICANN
+ VASSERT_EQ("2.1", "xn--hxajbheg2az3al", convertHelper("παράδειγμα", "utf-8", "idna"));
+ VASSERT_EQ("2.2", "xn--jxalpdlp", convertHelper("δοκιμή", "utf-8", "idna"));
+
+ VASSERT_EQ("3.1", "xn--mgbh0fb", convertHelper("مثال", "utf-8", "idna"));
+ VASSERT_EQ("3.2", "xn--kgbechtv", convertHelper("إختبار", "utf-8", "idna"));
+ }
+
+ void testDecodeIDNA() {
+
+ VASSERT_EQ("1", "español", convertHelper("xn--espaol-zwa", "idna", "utf-8"));
+
+ // Tests from ICANN
+ VASSERT_EQ("2.1", "παράδειγμα", convertHelper("xn--hxajbheg2az3al", "idna", "utf-8"));
+ VASSERT_EQ("2.2", "δοκιμή", convertHelper("xn--jxalpdlp", "idna", "utf-8"));
+
+ VASSERT_EQ("3.1", "مثال", convertHelper("xn--mgbh0fb", "idna", "utf-8"));
+ VASSERT_EQ("3.2", "إختبار", convertHelper("xn--kgbechtv", "idna", "utf-8"));
+ }
+
+ void testUTF7Support() {
+
+ // Ensure UTF-7 is supported, because it is used for IMAP
+ VASSERT_EQ("1", "VMime +- UTF-7 encoding", convertHelper("VMime + UTF-7 encoding", "utf-8", "utf-7"));
+ VASSERT_EQ("2", "f+APg-o", convertHelper("\x66\xc3\xb8\x6f", "utf-8", "utf-7"));
+ }
+
+ void testReplaceInvalidSequence() {
+
+ vmime::charsetConverterOptions opts;
+ opts.silentlyReplaceInvalidSequences = true;
+ opts.invalidSequence = "?";
+
+ vmime::string res = convertHelper(
+ "\x61\xf1\x80\x80\xe1\x80\xc2\x62\x80\x63\x80\xbf\x64",
+ "utf-8", "iso-8859-1", opts
+ );
+
+ // Result should be in the form "a???b?c??d" or "a??????b?c??d"...
+ // Remove consecutive question marks for easier matching.
+ res.erase(std::unique(res.begin(), res.end()), res.end());
+
+ VASSERT_EQ(
+ "Illegal UTF-8 sequence",
+ "a?b?c?d",
+ res
+ );
+ }
+
+ void testStopOnInvalidSequence() {
+
+ vmime::charsetConverterOptions opts;
+ opts.silentlyReplaceInvalidSequences = false;
+
+ VASSERT_THROW(
+ "Illegal UTF-8 sequence",
+ convertHelper("\x61\xf1\x80\x80\xe1\x80\xc2\x62\x80\x63\x80\xbf\x64", "utf-8", "iso-8859-1", opts),
+ vmime::exceptions::illegal_byte_sequence_for_charset
+ );
+ }
+
+ void testStatus() {
+
+ vmime::charsetConverterOptions opts;
+ opts.silentlyReplaceInvalidSequences = false;
+
+ vmime::charsetConverter::status st;
+
+ // 012345 6 7
+ convertHelper("Gwena\xc3\xabl", "utf-8", "iso-8859-1", opts, &st);
+
+ VASSERT_EQ("inputBytesRead", 8, st.inputBytesRead);
+ VASSERT_EQ("outputBytesWritten", 7, st.outputBytesWritten);
+ }
+
+ void testStatusWithInvalidSequence() {
+
+ vmime::charsetConverterOptions opts;
+ opts.silentlyReplaceInvalidSequences = false;
+
+ vmime::charsetConverter::status st;
+
+ try {
+
+ // 01234 5 6789 0 1
+ convertHelper("Fran\xc3\xa7ois\xf1\x80\x65", "utf-8", "iso-8859-1", opts, &st);
+
+ } catch (vmime::exceptions::illegal_byte_sequence_for_charset& e) {
+
+ } catch (...) {
+
+ throw;
+ }
+
+ VASSERT_EQ("inputBytesRead", 9, st.inputBytesRead);
+ VASSERT_EQ("outputBytesWritten", 8, st.outputBytesWritten);
+ }
+
+ void testIsValidText() {
+
+ // Invalid text
+ const vmime::string invalidText("Fran\xc3\xa7ois\xf1\x80\x65");
+ vmime::string::size_type firstInvalidByte;
+
+ VASSERT_EQ("invalid.isValidText", false, vmime::charset("utf-8").isValidText(invalidText, &firstInvalidByte));
+ VASSERT_EQ("invalid.firstInvalidByte", 9, firstInvalidByte);
+
+ // Valid text
+ const vmime::string validText("Gwena\xc3\xabl");
+
+ VASSERT_EQ("valid.isValidText", true, vmime::charset("utf-8").isValidText(validText, &firstInvalidByte));
+ VASSERT_EQ("valid.firstInvalidByte", 8, firstInvalidByte);
+ }
+
+VMIME_TEST_SUITE_END
diff --git a/vmime-master/tests/parser/charsetTestSuites.hpp b/vmime-master/tests/parser/charsetTestSuites.hpp
new file mode 100644
index 0000000..9653016
--- /dev/null
+++ b/vmime-master/tests/parser/charsetTestSuites.hpp
@@ -0,0 +1,102 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+
+struct charsetTestSuiteStruct {
+
+ const char* fromCharset;
+ const char* toCharset;
+ const char* fromBytes;
+ const unsigned int fromLength;
+ const char* toBytes;
+ const unsigned int toLength;
+};
+
+
+static const charsetTestSuiteStruct charsetTestSuites[] = {
+
+ // Test data 1 (excerpt from http://www.gnu.org)
+ {
+ "gb2312", "utf-8",
+
+ "\xbb\xb6\xd3\xad\xc0\xb4\xb5\xbd\x20\x47\x4e\x55\x20\xb9\xa4\xb3"
+ "\xcc\xb5\xc4\xcd\xf8\xd2\xb3\xcb\xc5\xb7\xfe\xd6\xf7\xbb\xfa\x20"
+ "\x77\x77\x77\x2e\x67\x6e\x75\x2e\x6f\x72\x67\x20\xa1\xa3\x20\x47"
+ "\x4e\x55\x20\xb9\xa4\xb3\xcc\x20\xbf\xaa\xca\xbc\xec\xb6\xd2\xbb"
+ "\xbe\xc5\xb0\xcb\xcb\xc4\xc4\xea\xa3\xac\xd6\xbc\xd4\xda\xb7\xa2"
+ "\xd5\xb9\xd2\xbb\xb8\xf6\xc0\xe0\xcb\xc6\x20\x55\x6e\x69\x78\x20"
+ "\xa3\xac\xc7\xd2\xce\xaa\x20\xd7\xd4\xd3\xc9\xc8\xed\xbc\xfe\x20"
+ "\xb5\xc4\xcd\xea\xd5\xfb\xb2\xd9\xd7\xf7\xcf\xb5\xcd\xb3\xa3\xba"
+ "\x20\x47\x4e\x55\x20\xcf\xb5\xcd\xb3\xa1\xa3\xa3\xa8\x47\x4e\x55"
+ "\x20\xca\xc7\xd3\xc9\xa1\xb0\x47\x4e\x55\x27\x73\x20\x4e\x6f\x74"
+ "\x20\x55\x6e\x69\x78\xa1\xb1\xcb\xf9\xb5\xdd\xbb\xd8\xb6\xa8\xd2"
+ "\xe5\xb3\xf6\xb5\xc4\xca\xd7\xd7\xd6\xc4\xb8\xcb\xf5\xd0\xb4\xd3"
+ "\xef\xa3\xbb\xcb\xfc\xb5\xc4\xb7\xa2\xd2\xf4\xce\xaa\xa1\xb0\x67"
+ "\x75\x68\x2d\x4e\x45\x57\xa1\xb1\xa3\xa9\xa1\xa3\xb8\xf7\xd6\xd6"
+ "\xca\xb9\xd3\xc3\x20\x4c\x69\x6e\x75\x78\x20\xd7\xf7\xce\xaa\xc4"
+ "\xda\xba\xcb\xb5\xc4\x20\x47\x4e\x55\x20\xb2\xd9\xd7\xf7\xcf\xb5"
+ "\xcd\xb3\xd5\xfd\xb1\xbb\xb9\xe3\xb7\xba\xb5\xd8\xca\xb9\xd3\xc3"
+ "\xd6\xf8\xa3\xbb\xcb\xe4\xc8\xbb\xd5\xe2\xd0\xa9\xcf\xb5\xcd\xb3"
+ "\xcd\xa8\xb3\xa3\xb1\xbb\xb3\xc6\xd7\xf7\xce\xaa\xa1\xb0\x4c\x69"
+ "\x6e\x75\x78\xa1\xb1\xa3\xac\xb5\xab\xca\xc7\xcb\xfc\xc3\xc7\xd3"
+ "\xa6\xb8\xc3\xb8\xfc\xbe\xab\xc8\xb7\xb5\xd8\xb1\xbb\xb3\xc6\xce"
+ "\xaa\x20\x47\x4e\x55\x2f\x4c\x69\x6e\x75\x78\x20\xcf\xb5\xcd\xb3"
+ "\x20\xa1\xa3\x0a",
+ 0,
+
+ "\xe6\xac\xa2\xe8\xbf\x8e\xe6\x9d\xa5\xe5\x88\xb0\x20\x47\x4e\x55"
+ "\x20\xe5\xb7\xa5\xe7\xa8\x8b\xe7\x9a\x84\xe7\xbd\x91\xe9\xa1\xb5"
+ "\xe4\xbc\xba\xe6\x9c\x8d\xe4\xb8\xbb\xe6\x9c\xba\x20\x77\x77\x77"
+ "\x2e\x67\x6e\x75\x2e\x6f\x72\x67\x20\xe3\x80\x82\x20\x47\x4e\x55"
+ "\x20\xe5\xb7\xa5\xe7\xa8\x8b\x20\xe5\xbc\x80\xe5\xa7\x8b\xe6\x96"
+ "\xbc\xe4\xb8\x80\xe4\xb9\x9d\xe5\x85\xab\xe5\x9b\x9b\xe5\xb9\xb4"
+ "\xef\xbc\x8c\xe6\x97\xa8\xe5\x9c\xa8\xe5\x8f\x91\xe5\xb1\x95\xe4"
+ "\xb8\x80\xe4\xb8\xaa\xe7\xb1\xbb\xe4\xbc\xbc\x20\x55\x6e\x69\x78"
+ "\x20\xef\xbc\x8c\xe4\xb8\x94\xe4\xb8\xba\x20\xe8\x87\xaa\xe7\x94"
+ "\xb1\xe8\xbd\xaf\xe4\xbb\xb6\x20\xe7\x9a\x84\xe5\xae\x8c\xe6\x95"
+ "\xb4\xe6\x93\x8d\xe4\xbd\x9c\xe7\xb3\xbb\xe7\xbb\x9f\xef\xbc\x9a"
+ "\x20\x47\x4e\x55\x20\xe7\xb3\xbb\xe7\xbb\x9f\xe3\x80\x82\xef\xbc"
+ "\x88\x47\x4e\x55\x20\xe6\x98\xaf\xe7\x94\xb1\xe2\x80\x9c\x47\x4e"
+ "\x55\x27\x73\x20\x4e\x6f\x74\x20\x55\x6e\x69\x78\xe2\x80\x9d\xe6"
+ "\x89\x80\xe9\x80\x92\xe5\x9b\x9e\xe5\xae\x9a\xe4\xb9\x89\xe5\x87"
+ "\xba\xe7\x9a\x84\xe9\xa6\x96\xe5\xad\x97\xe6\xaf\x8d\xe7\xbc\xa9"
+ "\xe5\x86\x99\xe8\xaf\xad\xef\xbc\x9b\xe5\xae\x83\xe7\x9a\x84\xe5"
+ "\x8f\x91\xe9\x9f\xb3\xe4\xb8\xba\xe2\x80\x9c\x67\x75\x68\x2d\x4e"
+ "\x45\x57\xe2\x80\x9d\xef\xbc\x89\xe3\x80\x82\xe5\x90\x84\xe7\xa7"
+ "\x8d\xe4\xbd\xbf\xe7\x94\xa8\x20\x4c\x69\x6e\x75\x78\x20\xe4\xbd"
+ "\x9c\xe4\xb8\xba\xe5\x86\x85\xe6\xa0\xb8\xe7\x9a\x84\x20\x47\x4e"
+ "\x55\x20\xe6\x93\x8d\xe4\xbd\x9c\xe7\xb3\xbb\xe7\xbb\x9f\xe6\xad"
+ "\xa3\xe8\xa2\xab\xe5\xb9\xbf\xe6\xb3\x9b\xe5\x9c\xb0\xe4\xbd\xbf"
+ "\xe7\x94\xa8\xe8\x91\x97\xef\xbc\x9b\xe8\x99\xbd\xe7\x84\xb6\xe8"
+ "\xbf\x99\xe4\xba\x9b\xe7\xb3\xbb\xe7\xbb\x9f\xe9\x80\x9a\xe5\xb8"
+ "\xb8\xe8\xa2\xab\xe7\xa7\xb0\xe4\xbd\x9c\xe4\xb8\xba\xe2\x80\x9c"
+ "\x4c\x69\x6e\x75\x78\xe2\x80\x9d\xef\xbc\x8c\xe4\xbd\x86\xe6\x98"
+ "\xaf\xe5\xae\x83\xe4\xbb\xac\xe5\xba\x94\xe8\xaf\xa5\xe6\x9b\xb4"
+ "\xe7\xb2\xbe\xe7\xa1\xae\xe5\x9c\xb0\xe8\xa2\xab\xe7\xa7\xb0\xe4"
+ "\xb8\xba\x20\x47\x4e\x55\x2f\x4c\x69\x6e\x75\x78\x20\xe7\xb3\xbb"
+ "\xe7\xbb\x9f\x20\xe3\x80\x82\x0a",
+ 0
+ }
+};
+
+static const vmime::size_t charsetTestSuitesCount = sizeof(charsetTestSuites) / sizeof(charsetTestSuites[0]);
diff --git a/vmime-master/tests/parser/datetimeTest.cpp b/vmime-master/tests/parser/datetimeTest.cpp
new file mode 100644
index 0000000..61c8522
--- /dev/null
+++ b/vmime-master/tests/parser/datetimeTest.cpp
@@ -0,0 +1,123 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "tests/testUtils.hpp"
+
+
+VMIME_TEST_SUITE_BEGIN(datetimeTest)
+
+ VMIME_TEST_LIST_BEGIN
+ VMIME_TEST(testParse)
+ VMIME_TEST(testGenerate)
+ VMIME_TEST(testCompare)
+ VMIME_TEST_LIST_END
+
+
+ void testParse() {
+
+ struct datetimePair {
+ vmime::string parseBuffer;
+ vmime::datetime result;
+ };
+
+ // Here, we can't test all the possible structures for date/time,
+ // so we test some cases. Don't forget to add a new test case
+ // each time you encounter a bug in date/time parsing (after
+ // you have fixed it).
+ datetimePair pairs[] = {
+
+ { /* 1 */ "Mon, 8 Nov 2004 13:42:56 +0000 (GMT)",
+ vmime::datetime(2004, 11, 8, 13, 42, 56, vmime::datetime::GMT) },
+
+ { /* 2 */ "Sun, 7 Nov 2004 00:43:22 -0500 (EST)",
+ vmime::datetime(2004, 11, 7, 0, 43, 22, vmime::datetime::GMT_5) },
+
+ { /* 3 */ "Thu Nov 18 12:11:16 2004",
+ vmime::datetime(vmime::datetime::now().getYear(), 11, 18, 12, 11, 16, vmime::datetime::GMT) },
+
+ { /* 4 */ "Sat, 18, 2004 22:36:32 -0400",
+ vmime::datetime(2004, 1, 18, 22, 36, 32, vmime::datetime::GMT_4) },
+
+ { /* 5 */ "Mon Dec 13 21:57:18 2004",
+ vmime::datetime(vmime::datetime::now().getYear(), 12, 13, 21, 57, 18, vmime::datetime::GMT) },
+
+ { /* 6 */ "18 Nov 2004 21:44:54 +0300",
+ vmime::datetime(2004, 11, 18, 21, 44, 54, vmime::datetime::GMT3) }
+ };
+
+ for (unsigned int i = 0 ; i < sizeof(pairs) / sizeof(pairs[0]) ; ++i) {
+
+ vmime::datetime d;
+ d.parse(pairs[i].parseBuffer);
+
+ std::ostringstream oss;
+ oss << (i + 1);
+
+ VASSERT_EQ(oss.str(), pairs[i].result, d);
+ }
+ }
+
+ void testGenerate() {
+
+ vmime::datetime d1(2005, 7, 8, 4, 5, 6, 1 * 60 + 23);
+
+ VASSERT_EQ("1", "Fri, 8 Jul 2005 04:05:06 +0123", d1.generate());
+ }
+
+ void testCompare() {
+
+ // Date1 = Date2
+ vmime::datetime d1(2005, 4, 22, 14, 6, 0, vmime::datetime::GMT2);
+ vmime::datetime d2(2005, 4, 22, 10, 6, 0, vmime::datetime::GMT_2);
+
+ VASSERT_EQ("1.1", true, d1 == d2);
+ VASSERT_EQ("1.2", false, d1 != d2);
+ VASSERT_EQ("1.3", true, d1 <= d2);
+ VASSERT_EQ("1.4", false, d1 < d2);
+ VASSERT_EQ("1.5", true, d1 >= d2);
+ VASSERT_EQ("1.6", false, d1 > d2);
+
+ // Date1 < Date2
+ vmime::datetime d3(2005, 4, 22, 14, 6, 0);
+ vmime::datetime d4(2005, 4, 22, 15, 6, 0);
+
+ VASSERT_EQ("2.1", false, d3 == d4);
+ VASSERT_EQ("2.2", true, d3 != d4);
+ VASSERT_EQ("2.3", true, d3 <= d4);
+ VASSERT_EQ("2.4", true, d3 < d4);
+ VASSERT_EQ("2.5", false, d3 >= d4);
+ VASSERT_EQ("2.6", false, d3 > d4);
+
+ // Date1 > Date2
+ vmime::datetime d5(2005, 4, 22, 15, 6, 0);
+ vmime::datetime d6(2005, 4, 22, 14, 6, 0);
+
+ VASSERT_EQ("3.1", false, d5 == d6);
+ VASSERT_EQ("3.2", true, d5 != d6);
+ VASSERT_EQ("3.3", false, d5 <= d6);
+ VASSERT_EQ("3.4", false, d5 < d6);
+ VASSERT_EQ("3.5", true, d5 >= d6);
+ VASSERT_EQ("3.6", true, d5 > d6);
+ }
+
+VMIME_TEST_SUITE_END
diff --git a/vmime-master/tests/parser/dispositionTest.cpp b/vmime-master/tests/parser/dispositionTest.cpp
new file mode 100644
index 0000000..f51c51e
--- /dev/null
+++ b/vmime-master/tests/parser/dispositionTest.cpp
@@ -0,0 +1,150 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "tests/testUtils.hpp"
+
+
+VMIME_TEST_SUITE_BEGIN(dispositionTest)
+
+ VMIME_TEST_LIST_BEGIN
+ VMIME_TEST(testParse)
+ VMIME_TEST(testGenerate)
+ VMIME_TEST(testModifiers)
+ VMIME_TEST_LIST_END
+
+
+ void testParse() {
+
+ // disposition-mode ";" disposition-type
+ // [ "/" disposition-modifier *( "," disposition-modifier ) ]
+ //
+ // disposition-mode = action-mode "/" sending-mode
+
+ vmime::disposition disp1;
+ disp1.parse("mode");
+
+ VASSERT_EQ("1.1", "mode", disp1.getActionMode());
+ VASSERT_EQ("1.2", "", disp1.getSendingMode());
+ VASSERT_EQ("1.3", "", disp1.getType());
+ VASSERT_EQ("1.4", 0, static_cast <int>(disp1.getModifierList().size()));
+
+ vmime::disposition disp2;
+ disp2.parse("amode/smode");
+
+ VASSERT_EQ("2.1", "amode", disp2.getActionMode());
+ VASSERT_EQ("2.2", "smode", disp2.getSendingMode());
+ VASSERT_EQ("2.3", "", disp2.getType());
+ VASSERT_EQ("2.4", 0, static_cast <int>(disp2.getModifierList().size()));
+
+ vmime::disposition disp3;
+ disp3.parse("amode/smode;type");
+
+ VASSERT_EQ("3.1", "amode", disp3.getActionMode());
+ VASSERT_EQ("3.2", "smode", disp3.getSendingMode());
+ VASSERT_EQ("3.3", "type", disp3.getType());
+ VASSERT_EQ("3.4", 0, static_cast <int>(disp3.getModifierList().size()));
+
+ vmime::disposition disp4;
+ disp4.parse("amode/smode;type/modif");
+
+ VASSERT_EQ("4.1", "amode", disp4.getActionMode());
+ VASSERT_EQ("4.2", "smode", disp4.getSendingMode());
+ VASSERT_EQ("4.3", "type", disp4.getType());
+ VASSERT_EQ("4.4", 1, static_cast <int>(disp4.getModifierList().size()));
+ VASSERT_EQ("4.5", "modif", disp4.getModifierList()[0]);
+
+ vmime::disposition disp5;
+ disp5.parse("amode/smode;type/modif1,modif2");
+
+ VASSERT_EQ("5.1", "amode", disp5.getActionMode());
+ VASSERT_EQ("5.2", "smode", disp5.getSendingMode());
+ VASSERT_EQ("5.3", "type", disp5.getType());
+ VASSERT_EQ("5.4", 2, static_cast <int>(disp5.getModifierList().size()));
+ VASSERT_EQ("5.5", "modif1", disp5.getModifierList()[0]);
+ VASSERT_EQ("5.6", "modif2", disp5.getModifierList()[1]);
+ }
+
+ void testGenerate() {
+
+ vmime::disposition disp;
+
+ VASSERT_EQ("1", "automatic-action/MDN-sent-automatically;displayed", disp.generate());
+
+ disp.setActionMode("amode");
+
+ VASSERT_EQ("2", "amode/MDN-sent-automatically;displayed", disp.generate());
+
+ disp.setActionMode("amode");
+ disp.setSendingMode("smode");
+
+ VASSERT_EQ("3", "amode/smode;displayed", disp.generate());
+
+ disp.setType("type");
+
+ VASSERT_EQ("4", "amode/smode;type", disp.generate());
+
+ disp.addModifier("modif1");
+
+ VASSERT_EQ("5", "amode/smode;type/modif1", disp.generate());
+
+ disp.addModifier("modif2");
+
+ VASSERT_EQ("6", "amode/smode;type/modif1,modif2", disp.generate());
+ }
+
+ void testModifiers() {
+
+ vmime::disposition disp1;
+
+ VASSERT_EQ("1", false, disp1.hasModifier("foo"));
+ VASSERT_EQ("2", 0, static_cast <int>(disp1.getModifierList().size()));
+
+ disp1.addModifier("bar");
+
+ VASSERT_EQ("3", false, disp1.hasModifier("foo"));
+ VASSERT_EQ("4", true, disp1.hasModifier("bar"));
+ VASSERT_EQ("5", 1, static_cast <int>(disp1.getModifierList().size()));
+
+ disp1.addModifier("plop");
+
+ VASSERT_EQ("6", false, disp1.hasModifier("foo"));
+ VASSERT_EQ("7", true, disp1.hasModifier("bar"));
+ VASSERT_EQ("8", true, disp1.hasModifier("plop"));
+ VASSERT_EQ("9", 2, static_cast <int>(disp1.getModifierList().size()));
+
+ disp1.removeModifier("bar");
+
+ VASSERT_EQ("10", false, disp1.hasModifier("foo"));
+ VASSERT_EQ("11", false, disp1.hasModifier("bar"));
+ VASSERT_EQ("12", true, disp1.hasModifier("plop"));
+ VASSERT_EQ("13", 1, static_cast <int>(disp1.getModifierList().size()));
+
+ disp1.removeModifier("PlOp");
+
+ VASSERT_EQ("14", false, disp1.hasModifier("foo"));
+ VASSERT_EQ("15", false, disp1.hasModifier("bar"));
+ VASSERT_EQ("16", false, disp1.hasModifier("plop"));
+ VASSERT_EQ("17", 0, static_cast <int>(disp1.getModifierList().size()));
+ }
+
+VMIME_TEST_SUITE_END
diff --git a/vmime-master/tests/parser/emailAddressTest.cpp b/vmime-master/tests/parser/emailAddressTest.cpp
new file mode 100644
index 0000000..f2a7070
--- /dev/null
+++ b/vmime-master/tests/parser/emailAddressTest.cpp
@@ -0,0 +1,281 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "tests/testUtils.hpp"
+
+#include "vmime/platform.hpp"
+
+#include <locale>
+#include <clocale>
+
+
+VMIME_TEST_SUITE_BEGIN(emailAddressTest)
+
+ VMIME_TEST_LIST_BEGIN
+ VMIME_TEST(testParseASCII)
+ VMIME_TEST(testParseEAI)
+ VMIME_TEST(testParseInvalid)
+ VMIME_TEST(testGenerateASCII)
+ VMIME_TEST(testGenerateEAI)
+ VMIME_TEST(testParseSpecialChars)
+ VMIME_TEST(testParseCommentInLocalPart)
+ VMIME_TEST(testParseCommentInDomainPart)
+ VMIME_TEST(testParseRFC2047EncodedLocalPart)
+ VMIME_TEST(testGenerateSpecialChars)
+ VMIME_TEST_LIST_END
+
+
+ void setUp() {
+
+ // Set the global C and C++ locale to the user-configured locale.
+ // The locale should use UTF-8 encoding for these tests to run successfully.
+ try {
+ std::locale::global(std::locale(""));
+ } catch (std::exception &) {
+ std::setlocale(LC_ALL, "");
+ }
+ }
+
+ void tearDown() {
+
+ // Restore default locale
+ std::locale::global(std::locale("C"));
+ }
+
+
+ void testParseASCII() {
+
+ vmime::emailAddress eml1("local@domain");
+ VASSERT_EQ("1/local", "local", eml1.getLocalName());
+ VASSERT_EQ("1/domain", "domain", eml1.getDomainName());
+
+ // When not specified, domain should be local host name
+ vmime::emailAddress eml2("local");
+ VASSERT_EQ("2/local", "local", eml2.getLocalName());
+ VASSERT_EQ("2/domain", vmime::platform::getHandler()->getHostName(), eml2.getDomainName());
+ }
+
+ void testParseEAI() {
+
+ // Examples taken from Wikipedia (http://en.wikipedia.org/wiki/Email_address)
+
+ // Latin Alphabet (with diacritics):
+ vmime::emailAddress eml1("Pelé@example.com");
+ VASSERT_EQ("1/local", "Pelé", eml1.getLocalName());
+ VASSERT_EQ("1/domain", "example.com", eml1.getDomainName());
+
+ // Greek Alphabet
+ vmime::emailAddress eml2("δοκιμή@παράδειγμα.δοκιμή");
+ VASSERT_EQ("2/local", "δοκιμή", eml2.getLocalName());
+ VASSERT_EQ("2/domain", "παράδειγμα.δοκιμή", eml2.getDomainName());
+
+ // Japanese Characters
+ vmime::emailAddress eml3("甲斐@黒川.日本");
+ VASSERT_EQ("3/local", "甲斐", eml3.getLocalName());
+ VASSERT_EQ("3/domain", "黒川.日本", eml3.getDomainName());
+
+ // Cyrillic Characters
+ vmime::emailAddress eml4("чебурашка@ящик-с-апельсинами.рф");
+ VASSERT_EQ("4/local", "чебурашка", eml4.getLocalName());
+ VASSERT_EQ("4/domain", "ящик-с-апельсинами.рф", eml4.getDomainName());
+ }
+
+ void testParseInvalid() {
+
+ // Only one @ is allowed outside quotation marks
+ vmime::emailAddress eml1("local@part@domain");
+ VASSERT_EQ("1/local", "local", eml1.getLocalName());
+ VASSERT_EQ("1/domain", "part@domain", eml1.getDomainName());
+
+ // Quoted strings must be dot separated, or the only element making up
+ // the local-part: should be parsed correctly, but it still represents
+ // an invalid email address
+ vmime::emailAddress eml2("Just\"not\"right@example.com");
+ VASSERT_EQ("2/local", "Just\"not\"right", eml2.getLocalName());
+ VASSERT_EQ("2/domain", "example.com", eml2.getDomainName());
+
+ // An @ character must separate the local and domain parts
+ vmime::emailAddress eml3("Abc.example.com");
+ VASSERT_EQ("3/local", "Abc.example.com", eml3.getLocalName());
+ VASSERT_EQ("3/domain", vmime::platform::getHandler()->getHostName(), eml3.getDomainName());
+
+ // Whitespace must be escaped
+ vmime::emailAddress eml4("local part@domain");
+ VASSERT_EQ("4/local", "local", eml4.getLocalName());
+ VASSERT_EQ("4/domain", vmime::platform::getHandler()->getHostName(), eml4.getDomainName());
+
+ vmime::emailAddress eml5("this\\ still\\\"not\\\\allowed@example.com");
+ VASSERT_EQ("5/local", "this\\", eml5.getLocalName());
+ VASSERT_EQ("5/domain", vmime::platform::getHandler()->getHostName(), eml5.getDomainName());
+ }
+
+ void testParseSpecialChars() {
+
+ // Examples taken from Wikipedia (http://en.wikipedia.org/wiki/Email_address)
+
+ vmime::emailAddress eml1("\" \"@example.org");
+ VASSERT_EQ("1/local", " ", eml1.getLocalName());
+ VASSERT_EQ("1/domain", "example.org", eml1.getDomainName());
+
+ vmime::emailAddress eml2("\"()<>[]:,;@\\\\\\\"!#$%&'*+-/=?^_`{}| ~.a\"@example.org");
+ VASSERT_EQ("2/local", "()<>[]:,;@\\\"!#$%&'*+-/=?^_`{}| ~.a", eml2.getLocalName());
+ VASSERT_EQ("3/domain", "example.org", eml2.getDomainName());
+
+ vmime::emailAddress eml3("!#$%&'*+-/=?^_`{}|~@example.org");
+ VASSERT_EQ("3/local", "!#$%&'*+-/=?^_`{}|~", eml3.getLocalName());
+ VASSERT_EQ("3/domain", "example.org", eml3.getDomainName());
+
+ vmime::emailAddress eml4("!#$%&'*+-/=?^_`{}|~@example.org");
+ VASSERT_EQ("4/local", "!#$%&'*+-/=?^_`{}|~", eml4.getLocalName());
+ VASSERT_EQ("4/domain", "example.org", eml4.getDomainName());
+
+ vmime::emailAddress eml5("\"very.unusual.@.unusual.com\"@example.com");
+ VASSERT_EQ("5/local", "very.unusual.@.unusual.com", eml5.getLocalName());
+ VASSERT_EQ("5/domain", "example.com", eml5.getDomainName());
+
+ vmime::emailAddress eml6("\"very.(),:;<>[]\\\".VERY.\\\"very@\\\\ \\\"very\\\".unusual\"@strange.example.com");
+ VASSERT_EQ("6/local", "very.(),:;<>[]\".VERY.\"very@\\ \"very\".unusual", eml6.getLocalName());
+ VASSERT_EQ("6/domain", "strange.example.com", eml6.getDomainName());
+ }
+
+ void testParseCommentInLocalPart() {
+
+ vmime::emailAddress eml1("john.smith(comment)@example.com");
+ VASSERT_EQ("1/local", "john.smith", eml1.getLocalName());
+ VASSERT_EQ("1/domain", "example.com", eml1.getDomainName());
+
+ vmime::emailAddress eml2("(comment)john.smith@example.com");
+ VASSERT_EQ("2/local", "john.smith", eml2.getLocalName());
+ VASSERT_EQ("2/domain", "example.com", eml2.getDomainName());
+
+ vmime::emailAddress eml3("(comment (comment in comment))john.smith@example.com");
+ VASSERT_EQ("3/local", "john.smith", eml3.getLocalName());
+ VASSERT_EQ("3/domain", "example.com", eml3.getDomainName());
+
+ vmime::emailAddress eml4("(comment \\) end comment)john.smith@example.com");
+ VASSERT_EQ("4/local", "john.smith", eml4.getLocalName());
+ VASSERT_EQ("4/domain", "example.com", eml4.getDomainName());
+ }
+
+ void testParseCommentInDomainPart() {
+
+ vmime::emailAddress eml1("john.smith@(comment)example.com");
+ VASSERT_EQ("1/local", "john.smith", eml1.getLocalName());
+ VASSERT_EQ("1/domain", "example.com", eml1.getDomainName());
+
+ vmime::emailAddress eml2("john.smith@example.com(comment)");
+ VASSERT_EQ("2/local", "john.smith", eml2.getLocalName());
+ VASSERT_EQ("2/domain", "example.com", eml2.getDomainName());
+
+ vmime::emailAddress eml3("john.smith@(comment (comment in comment))example.com");
+ VASSERT_EQ("3/local", "john.smith", eml3.getLocalName());
+ VASSERT_EQ("3/domain", "example.com", eml3.getDomainName());
+
+ vmime::emailAddress eml4("john.smith@(comment \\) end comment)example.com");
+ VASSERT_EQ("4/local", "john.smith", eml4.getLocalName());
+ VASSERT_EQ("4/domain", "example.com", eml4.getDomainName());
+ }
+
+ void testParseRFC2047EncodedLocalPart() {
+
+ vmime::emailAddress eml1("=?utf-8?Q?Pel=C3=A9?=@example.com");
+ VASSERT_EQ("1/local", "Pelé", eml1.getLocalName());
+ VASSERT_EQ("1/domain", "example.com", eml1.getDomainName());
+
+ vmime::emailAddress eml2("=?utf-8?B?55Sy5paQ?=@xn--5rtw95l.xn--wgv71a");
+ VASSERT_EQ("2/local", "甲斐", eml2.getLocalName());
+ VASSERT_EQ("2/domain", "黒川.日本", eml2.getDomainName());
+
+ vmime::emailAddress eml3("=?utf-8?B?55Sy5paQ?=@xn--5rtw95l.com");
+ VASSERT_EQ("3/local", "甲斐", eml3.getLocalName());
+ VASSERT_EQ("3/domain", "黒川.com", eml3.getDomainName());
+ }
+
+ void testGenerateASCII() {
+
+ VASSERT_EQ(
+ "email 1", "local@domain",
+ vmime::emailAddress("local", "domain").generate()
+ );
+ VASSERT_EQ(
+ "email 2", "=?utf-8?Q?Pel=C3=A9?=@example.com",
+ vmime::emailAddress("Pelé", "example.com").generate()
+ );
+ VASSERT_EQ(
+ "email 3", "=?utf-8?B?55Sy5paQ?=@xn--5rtw95l.xn--wgv71a",
+ vmime::emailAddress("甲斐", "黒川.日本").generate()
+ );
+ VASSERT_EQ(
+ "email 4", "mailtest@xn--r8jz45g.xn--zckzah",
+ vmime::emailAddress("mailtest", "例え.テスト").generate()
+ );
+ VASSERT_EQ(
+ "email 5", "mailtest@xn--mgbh0fb.xn--kgbechtv",
+ vmime::emailAddress("mailtest", "مثال.إختبار").generate()
+ );
+ }
+
+ void testGenerateEAI() {
+
+ vmime::generationContext ctx(vmime::generationContext::getDefaultContext());
+ ctx.setInternationalizedEmailSupport(true);
+
+ vmime::generationContext::switcher <vmime::generationContext> contextSwitcher(ctx);
+
+ VASSERT_EQ(
+ "email 1", "Pelé@example.com",
+ vmime::emailAddress("Pelé", "example.com").generate()
+ );
+ VASSERT_EQ(
+ "email 2", "δοκιμή@παράδειγμα.δοκιμή",
+ vmime::emailAddress("δοκιμή", "παράδειγμα.δοκιμή").generate()
+ );
+ VASSERT_EQ(
+ "email 3", "甲斐@黒川.日本",
+ vmime::emailAddress("甲斐", "黒川.日本").generate()
+ );
+ VASSERT_EQ(
+ "email 4", "чебурашка@ящик-с-апельсинами.рф",
+ vmime::emailAddress("чебурашка", "ящик-с-апельсинами.рф").generate()
+ );
+ }
+
+ void testGenerateSpecialChars() {
+
+ VASSERT_EQ(
+ "email 1", "\"very.unusual.@.unusual.com\"@example.com",
+ vmime::emailAddress("very.unusual.@.unusual.com", "example.com").generate()
+ );
+
+ VASSERT_EQ(
+ "email 2", "\"very.(),:;<>[]\\\".VERY.\\\"very@\\\\ \\\"very\\\".unusual\"@strange.example.com",
+ vmime::emailAddress("very.(),:;<>[]\".VERY.\"very@\\ \"very\".unusual", "strange.example.com").generate()
+ );
+
+ VASSERT_EQ(
+ "email 3", "\" \"@example.com",
+ vmime::emailAddress(" ", "example.com").generate()
+ );
+ }
+
+VMIME_TEST_SUITE_END
diff --git a/vmime-master/tests/parser/emptyContentHandlerTest.cpp b/vmime-master/tests/parser/emptyContentHandlerTest.cpp
new file mode 100644
index 0000000..43cd8c2
--- /dev/null
+++ b/vmime-master/tests/parser/emptyContentHandlerTest.cpp
@@ -0,0 +1,99 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "tests/testUtils.hpp"
+
+#include "vmime/utility/outputStreamAdapter.hpp"
+
+
+VMIME_TEST_SUITE_BEGIN(emptyContentHandlerTest)
+
+ VMIME_TEST_LIST_BEGIN
+ VMIME_TEST(testIsEmpty)
+ VMIME_TEST(testGetLength)
+ VMIME_TEST(testIsEncoded)
+ VMIME_TEST(testExtract)
+ VMIME_TEST(testExtractRaw)
+ VMIME_TEST(testGenerate)
+ VMIME_TEST_LIST_END
+
+
+ void testIsEmpty() {
+
+ vmime::emptyContentHandler cth;
+
+ VASSERT_TRUE("empty", cth.isEmpty());
+ }
+
+ void testGetLength() {
+
+ vmime::emptyContentHandler cth;
+
+ VASSERT_EQ("length", 0, cth.getLength());
+ }
+
+ void testIsEncoded() {
+
+ vmime::emptyContentHandler cth;
+
+ VASSERT_FALSE("encoded", cth.isEncoded());
+ VASSERT_EQ("encoding", vmime::contentHandler::NO_ENCODING, cth.getEncoding());
+ }
+
+ void testExtract() {
+
+ vmime::emptyContentHandler cth;
+
+ std::ostringstream oss;
+ vmime::utility::outputStreamAdapter osa(oss);
+
+ cth.extract(osa);
+
+ VASSERT_EQ("extract", "", oss.str());
+ }
+
+ void testExtractRaw() {
+
+ vmime::emptyContentHandler cth;
+
+ std::ostringstream oss;
+ vmime::utility::outputStreamAdapter osa(oss);
+
+ cth.extractRaw(osa);
+
+ VASSERT_EQ("extractRaw", "", oss.str());
+ }
+
+ void testGenerate() {
+
+ vmime::emptyContentHandler cth;
+
+ std::ostringstream oss;
+ vmime::utility::outputStreamAdapter osa(oss);
+
+ cth.generate(osa, vmime::encoding("base64"));
+
+ VASSERT_EQ("generate", "", oss.str());
+ }
+
+VMIME_TEST_SUITE_END
diff --git a/vmime-master/tests/parser/fileContentHandlerTest.cpp b/vmime-master/tests/parser/fileContentHandlerTest.cpp
new file mode 100644
index 0000000..e979b52
--- /dev/null
+++ b/vmime-master/tests/parser/fileContentHandlerTest.cpp
@@ -0,0 +1,134 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "tests/testUtils.hpp"
+
+#include "vmime/utility/outputStreamAdapter.hpp"
+
+
+VMIME_TEST_SUITE_BEGIN(fileContentHandlerTest)
+
+ VMIME_TEST_LIST_BEGIN
+ VMIME_TEST(testIsEmpty)
+ VMIME_TEST(testGetLength)
+ VMIME_TEST(testIsEncoded)
+ VMIME_TEST(testExtract)
+ VMIME_TEST(testExtractRaw)
+ VMIME_TEST(testGenerate)
+ VMIME_TEST_LIST_END
+
+
+ vmime::shared_ptr <vmime::utility::file> testFile;
+ vmime::string testDataEncoded, testDataDecoded;
+
+
+ void setUp() {
+
+ testDataDecoded = "ABCDEFGHIJKLMNOPQRSTUVWXYZ \x12\x34\x56\x78\x90 abcdefghijklmnopqrstuvwxyz0123456789";
+ testDataEncoded = "QUJDREVGR0hJSktMTU5PUFFSU1RVVldYWVogEjRWeJAgYWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXowMTIzNDU2Nzg5";
+
+ std::ostringstream testFilePath;
+ testFilePath << "/tmp/vmime_test_" << (rand() % 999999999);
+
+ vmime::shared_ptr <vmime::utility::fileSystemFactory> fsf =
+ vmime::platform::getHandler()->getFileSystemFactory();
+
+ testFile = fsf->create(fsf->stringToPath(testFilePath.str()));
+ testFile->createFile();
+ testFile->getFileWriter()->getOutputStream()->write(testDataEncoded.data(), testDataEncoded.length());
+ }
+
+ void tearDown() {
+
+ testFile->remove();
+ testFile = vmime::null;
+ }
+
+
+ void testIsEmpty() {
+
+ vmime::fileContentHandler cth;
+
+ VASSERT_TRUE("empty", cth.isEmpty());
+ }
+
+ void testGetLength() {
+
+ vmime::fileContentHandler cth(testFile);
+
+ VASSERT_FALSE("empty", cth.isEmpty());
+ VASSERT_EQ("length", testDataEncoded.length(), cth.getLength());
+ }
+
+ void testIsEncoded() {
+
+ vmime::fileContentHandler cth(testFile, vmime::encoding("base64"));
+
+ VASSERT_TRUE("encoded", cth.isEncoded());
+ VASSERT_EQ("encoding", "base64", cth.getEncoding().generate());
+ }
+
+ void testExtract() {
+
+ vmime::fileContentHandler cth(testFile, vmime::encoding("base64"));
+
+ std::ostringstream oss;
+ vmime::utility::outputStreamAdapter osa(oss);
+
+ cth.extract(osa);
+
+ // Data should be decoded from B64
+ VASSERT_EQ("extract", testDataDecoded, oss.str());
+ }
+
+ void testExtractRaw() {
+
+ vmime::fileContentHandler cth(testFile, vmime::encoding("base64"));
+
+ std::ostringstream oss;
+ vmime::utility::outputStreamAdapter osa(oss);
+
+ cth.extractRaw(osa);
+
+ // Data should not be decoded
+ VASSERT_EQ("extractRaw", testDataEncoded, oss.str());
+ }
+
+ void testGenerate() {
+
+ vmime::fileContentHandler cth(testFile, vmime::encoding("base64"));
+
+ std::ostringstream oss;
+ vmime::utility::outputStreamAdapter osa(oss);
+
+ cth.generate(osa, vmime::encoding("quoted-printable"));
+
+ // Data should be reencoded from B64 to QP
+ VASSERT_EQ(
+ "generate",
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZ =124Vx=90 abcdefghijklmnopqrstuvwxyz0123456789",
+ oss.str()
+ );
+ }
+
+VMIME_TEST_SUITE_END
diff --git a/vmime-master/tests/parser/headerFieldTest.cpp b/vmime-master/tests/parser/headerFieldTest.cpp
new file mode 100644
index 0000000..78d0480
--- /dev/null
+++ b/vmime-master/tests/parser/headerFieldTest.cpp
@@ -0,0 +1,112 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "tests/testUtils.hpp"
+
+
+VMIME_TEST_SUITE_BEGIN(headerFieldTest)
+
+ VMIME_TEST_LIST_BEGIN
+ VMIME_TEST(testBadValueType)
+ VMIME_TEST(testValueOnNextLine)
+ VMIME_TEST(testStripSpacesAtEnd)
+ VMIME_TEST(testValueWithEmptyLine)
+ VMIME_TEST_LIST_END
+
+
+ void testBadValueType() {
+
+ vmime::shared_ptr <vmime::headerFieldFactory> hfactory =
+ vmime::headerFieldFactory::getInstance();
+
+ // "To" header field accepts values of type "addressList"
+ vmime::shared_ptr <vmime::headerField> to = hfactory->create(vmime::fields::TO);
+
+ VASSERT_THROW(
+ "to",
+ to->setValue(vmime::mailbox("email@vmime.org")),
+ vmime::exceptions::bad_field_value_type
+ );
+
+ // Unregistered header field accepts any value type
+ vmime::shared_ptr <vmime::headerField> custom = hfactory->create("X-MyCustomHeader");
+
+ VASSERT_NO_THROW(
+ "custom/1",
+ custom->setValue(vmime::mailbox("email@vmime.org"))
+ );
+ VASSERT_NO_THROW(
+ "custom/2",
+ custom->setValue(vmime::text("field value text"))
+ );
+ }
+
+ void testValueOnNextLine() {
+
+ vmime::parsingContext ctx;
+
+ const vmime::string buffer = "Field: \r\n\tfield data";
+
+ vmime::shared_ptr <vmime::headerField> hfield =
+ vmime::headerField::parseNext(ctx, buffer, 0, buffer.size());
+
+ vmime::shared_ptr <vmime::text> hvalue =
+ hfield->getValue <vmime::text>();
+
+ VASSERT_EQ("Field name", "Field", hfield->getName());
+ VASSERT_EQ("Field value", "field data", hvalue->getWholeBuffer());
+ }
+
+ void testStripSpacesAtEnd() {
+
+ vmime::parsingContext ctx;
+
+ const vmime::string buffer = "Field: \r\n\tfield data ";
+
+ vmime::shared_ptr <vmime::headerField> hfield =
+ vmime::headerField::parseNext(ctx, buffer, 0, buffer.size());
+
+ vmime::shared_ptr <vmime::text> hvalue =
+ hfield->getValue <vmime::text>();
+
+ VASSERT_EQ("Field name", "Field", hfield->getName());
+ VASSERT_EQ("Field value", toHex("field data"), toHex(hvalue->getWholeBuffer()));
+ }
+
+ void testValueWithEmptyLine() {
+
+ vmime::parsingContext ctx;
+
+ const vmime::string buffer = "Field: \r\n\tdata1\r\n\tdata2\r\n\t\r\n\tdata3";
+
+ vmime::shared_ptr <vmime::headerField> hfield =
+ vmime::headerField::parseNext(ctx, buffer, 0, buffer.size());
+
+ vmime::shared_ptr <vmime::text> hvalue =
+ hfield->getValue <vmime::text>();
+
+ VASSERT_EQ("Field name", "Field", hfield->getName());
+ VASSERT_EQ("Field value", "data1 data2 data3", hvalue->getWholeBuffer());
+ }
+
+VMIME_TEST_SUITE_END
diff --git a/vmime-master/tests/parser/headerTest.cpp b/vmime-master/tests/parser/headerTest.cpp
new file mode 100644
index 0000000..839acee
--- /dev/null
+++ b/vmime-master/tests/parser/headerTest.cpp
@@ -0,0 +1,375 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "tests/testUtils.hpp"
+
+
+VMIME_TEST_SUITE_BEGIN(headerTest)
+
+ VMIME_TEST_LIST_BEGIN
+ VMIME_TEST(testHas1)
+ VMIME_TEST(testHas2)
+
+ VMIME_TEST(testAppend1)
+ VMIME_TEST(testAppend2)
+
+ VMIME_TEST(testInsertFieldBefore1)
+ VMIME_TEST(testInsertFieldBefore2)
+
+ VMIME_TEST(testInsertFieldAfter1)
+ VMIME_TEST(testInsertFieldAfter2)
+
+ VMIME_TEST(testReplaceField)
+
+ VMIME_TEST(testRemoveField1)
+ VMIME_TEST(testRemoveField2)
+
+ VMIME_TEST(testRemoveAllFields)
+
+ VMIME_TEST(testgetFieldCount)
+
+ VMIME_TEST(testIsEmpty1)
+ VMIME_TEST(testIsEmpty2)
+
+ VMIME_TEST(testGetFieldAt)
+
+ VMIME_TEST(testGetFieldList1)
+ VMIME_TEST(testGetFieldList2)
+
+ VMIME_TEST(testFind1)
+
+ VMIME_TEST(testFindAllFields1)
+ VMIME_TEST(testFindAllFields2)
+ VMIME_TEST(testFindAllFields3)
+ VMIME_TEST_LIST_END
+
+
+ static const std::string getFieldValue(const vmime::headerField& field) {
+
+ std::ostringstream oss;
+ vmime::utility::outputStreamAdapter voss(oss);
+ field.generate(voss);
+
+ return oss.str();
+ }
+
+ // has function tests
+ void testHas1() {
+
+ vmime::header hdr;
+ hdr.parse("From: x\r\nTo: y\r\nTo: z\r\n");
+
+ bool res = hdr.hasField("Z");
+
+ VASSERT_EQ("Value", false, res);
+ }
+
+ void testHas2() {
+
+ vmime::header hdr;
+ hdr.parse("X: x\r\nTo: y\r\nTo: z\r\n");
+
+ bool res = hdr.hasField("To");
+
+ VASSERT_EQ("Value", true, res);
+ }
+
+ // appendField function tests
+ void testAppend1() {
+
+ vmime::header hdr;
+ hdr.parse("");
+
+ vmime::shared_ptr <vmime::headerField> hf = vmime::headerFieldFactory::getInstance()->create("A", "a");
+ hdr.appendField(hf);
+
+ std::vector <vmime::shared_ptr <vmime::headerField> > res = hdr.getFieldList();
+
+ VASSERT_EQ("Count", static_cast <unsigned int>(1), res.size());
+ VASSERT_EQ("First value", "A: a", headerTest::getFieldValue(*res[0]));
+ }
+
+ void testAppend2() {
+
+ vmime::header hdr;
+ hdr.parse("A: a\r\n");
+
+ vmime::shared_ptr <vmime::headerField> hf = vmime::headerFieldFactory::getInstance()->create("B", "b");
+ hdr.appendField(hf);
+
+ std::vector <vmime::shared_ptr <vmime::headerField> > res = hdr.getFieldList();
+
+ VASSERT_EQ("Count", static_cast <unsigned int>(2), res.size());
+ VASSERT_EQ("First value", "A: a", headerTest::getFieldValue(*res[0]));
+ VASSERT_EQ("Second value", "B: b", headerTest::getFieldValue(*res[1]));
+ }
+
+ // insertFieldBefore
+ void testInsertFieldBefore1() {
+
+ vmime::header hdr;
+ hdr.parse("A: a\r\nC: c\r\n");
+
+ vmime::shared_ptr <vmime::headerField> hf = vmime::headerFieldFactory::getInstance()->create("B", "b");
+ hdr.insertFieldBefore(hdr.getField("C"), hf);
+
+ std::vector <vmime::shared_ptr <vmime::headerField> > res = hdr.getFieldList();
+
+ VASSERT_EQ("Count", static_cast <unsigned int>(3), res.size());
+ VASSERT_EQ("First value", "A: a", headerTest::getFieldValue(*res[0]));
+ VASSERT_EQ("Second value", "B: b", headerTest::getFieldValue(*res[1]));
+ VASSERT_EQ("Third value", "C: c", headerTest::getFieldValue(*res[2]));
+ }
+
+ void testInsertFieldBefore2() {
+
+ vmime::header hdr;
+ hdr.parse("A: a\r\nC: c\r\n");
+
+ vmime::shared_ptr <vmime::headerField> hf = vmime::headerFieldFactory::getInstance()->create("B", "b");
+ hdr.insertFieldBefore(1, hf);
+
+ std::vector <vmime::shared_ptr <vmime::headerField> > res = hdr.getFieldList();
+
+ VASSERT_EQ("Count", static_cast <unsigned int>(3), res.size());
+ VASSERT_EQ("First value", "A: a", headerTest::getFieldValue(*res[0]));
+ VASSERT_EQ("Second value", "B: b", headerTest::getFieldValue(*res[1]));
+ VASSERT_EQ("Third value", "C: c", headerTest::getFieldValue(*res[2]));
+ }
+
+ // insertFieldAfter
+ void testInsertFieldAfter1() {
+
+ vmime::header hdr;
+ hdr.parse("A: a\r\nC: c\r\n");
+
+ vmime::shared_ptr <vmime::headerField> hf = vmime::headerFieldFactory::getInstance()->create("B", "b");
+ hdr.insertFieldAfter(hdr.getField("A"), hf);
+
+ std::vector <vmime::shared_ptr <vmime::headerField> > res = hdr.getFieldList();
+
+ VASSERT_EQ("Count", static_cast <unsigned int>(3), res.size());
+ VASSERT_EQ("First value", "A: a", headerTest::getFieldValue(*res[0]));
+ VASSERT_EQ("Second value", "B: b", headerTest::getFieldValue(*res[1]));
+ VASSERT_EQ("Third value", "C: c", headerTest::getFieldValue(*res[2]));
+ }
+
+ void testInsertFieldAfter2() {
+
+ vmime::header hdr;
+ hdr.parse("A: a\r\nC: c\r\n");
+
+ vmime::shared_ptr <vmime::headerField> hf = vmime::headerFieldFactory::getInstance()->create("B", "b");
+ hdr.insertFieldAfter(0, hf);
+
+ std::vector <vmime::shared_ptr <vmime::headerField> > res = hdr.getFieldList();
+
+ VASSERT_EQ("Count", static_cast <unsigned int>(3), res.size());
+ VASSERT_EQ("First value", "A: a", headerTest::getFieldValue(*res[0]));
+ VASSERT_EQ("Second value", "B: b", headerTest::getFieldValue(*res[1]));
+ VASSERT_EQ("Third value", "C: c", headerTest::getFieldValue(*res[2]));
+ }
+
+ // replaceField
+ void testReplaceField() {
+
+ vmime::header hdr;
+ hdr.parse("A: a\r\nB: b\r\nC: c\r\n");
+
+ vmime::shared_ptr <vmime::headerField> hf = vmime::headerFieldFactory::getInstance()->create("Z", "z");
+ hdr.replaceField(hdr.getField("B"), hf);
+
+ std::vector <vmime::shared_ptr <vmime::headerField> > res = hdr.getFieldList();
+
+ VASSERT_EQ("Count", static_cast <unsigned int>(3), res.size());
+ VASSERT_EQ("First value", "A: a", headerTest::getFieldValue(*res[0]));
+ VASSERT_EQ("Second value", "Z: z", headerTest::getFieldValue(*res[1]));
+ VASSERT_EQ("Third value", "C: c", headerTest::getFieldValue(*res[2]));
+ }
+
+ // removeField
+ void testRemoveField1() {
+
+ vmime::header hdr1, hdr2;
+ hdr1.parse("A: a\r\nB: b\r\nC: c\r\n");
+ hdr2.parse("A: a\r\nB: b\r\nC: c\r\n");
+
+ hdr1.removeField(hdr1.getField("B"));
+ hdr2.removeField(1);
+
+ std::vector <vmime::shared_ptr <vmime::headerField> > res1 = hdr1.getFieldList();
+
+ VASSERT_EQ("Count", static_cast <unsigned int>(2), res1.size());
+ VASSERT_EQ("First value", "A: a", headerTest::getFieldValue(*res1[0]));
+ VASSERT_EQ("Second value", "C: c", headerTest::getFieldValue(*res1[1]));
+
+ std::vector <vmime::shared_ptr <vmime::headerField> > res2 = hdr2.getFieldList();
+
+ VASSERT_EQ("Count", static_cast <unsigned int>(2), res2.size());
+ VASSERT_EQ("First value", "A: a", headerTest::getFieldValue(*res2[0]));
+ VASSERT_EQ("Second value", "C: c", headerTest::getFieldValue(*res2[1]));
+ }
+
+ void testRemoveField2() {
+
+ vmime::header hdr1, hdr2;
+ hdr1.parse("A: a\r\n");
+ hdr2.parse("A: a\r\n");
+
+ hdr1.removeField(hdr1.getField("A"));
+ hdr2.removeField(0);
+
+ std::vector <vmime::shared_ptr <vmime::headerField> > res1 = hdr1.getFieldList();
+ VASSERT_EQ("Count", static_cast <unsigned int>(0), res1.size());
+
+ std::vector <vmime::shared_ptr <vmime::headerField> > res2 = hdr2.getFieldList();
+ VASSERT_EQ("Count", static_cast <unsigned int>(0), res2.size());
+ }
+
+ // removeAllFields
+ void testRemoveAllFields() {
+
+ vmime::header hdr1, hdr2;
+ hdr1.parse("A: a\r\n");
+ hdr2.parse("A: a\r\nB: b\r\n");
+
+ hdr1.removeAllFields();
+ hdr2.removeAllFields();
+
+ std::vector <vmime::shared_ptr <vmime::headerField> > res1 = hdr1.getFieldList();
+ VASSERT_EQ("Count", static_cast <unsigned int>(0), res1.size());
+
+ std::vector <vmime::shared_ptr <vmime::headerField> > res2 = hdr2.getFieldList();
+ VASSERT_EQ("Count", static_cast <unsigned int>(0), res2.size());
+ }
+
+ // getFieldCount
+ void testgetFieldCount() {
+
+ vmime::header hdr;
+ hdr.parse("A: a\r\nB: b\r\nC: c\r\nD: d\r\n");
+
+ VASSERT_EQ("Value", 4, hdr.getFieldCount());
+ }
+
+ // isEmpty
+ void testIsEmpty1() {
+
+ vmime::header hdr;
+ hdr.parse("A: a\r\nB: b\r\nC: c\r\n");
+
+ VASSERT_EQ("Value", false, hdr.isEmpty());
+ }
+
+ void testIsEmpty2() {
+
+ vmime::header hdr;
+ hdr.parse("\r\n");
+
+ VASSERT_EQ("Value", true, hdr.isEmpty());
+ }
+
+ // getFieldAt
+ void testGetFieldAt() {
+
+ vmime::header hdr;
+ hdr.parse("B: b\r\nA: a\r\nC: c\r\n");
+
+ vmime::shared_ptr <vmime::headerField> res = hdr.getFieldAt(2);
+
+ VASSERT_EQ("Value", "C: c", getFieldValue(*res));
+ }
+
+ // getFieldList
+ void testGetFieldList1() {
+
+ vmime::header hdr;
+ hdr.parse("A: a\r\nB: b1\r\nC: c\r\nB: b2\r\n");
+
+ std::vector <vmime::shared_ptr <vmime::headerField> > res = hdr.getFieldList();
+
+ VASSERT_EQ("Count", static_cast <unsigned int>(4), res.size());
+ VASSERT_EQ("First value", "A: a", headerTest::getFieldValue(*res[0]));
+ VASSERT_EQ("Second value", "B: b1", headerTest::getFieldValue(*res[1]));
+ VASSERT_EQ("Third value", "C: c", headerTest::getFieldValue(*res[2]));
+ VASSERT_EQ("Thourth value", "B: b2", headerTest::getFieldValue(*res[3]));
+ }
+
+ void testGetFieldList2() {
+
+ vmime::header hdr;
+ hdr.parse("\r\n");
+
+ std::vector <vmime::shared_ptr <vmime::headerField> > res = hdr.getFieldList();
+
+ VASSERT_EQ("Count", static_cast <unsigned int>(0), res.size());
+ }
+
+ // find function tests
+ void testFind1() {
+
+ vmime::header hdr;
+ hdr.parse("A: a\r\nB: b\r\nC: c\r\nB: d\r\n");
+
+ vmime::shared_ptr <vmime::headerField> res = hdr.findField("B");
+
+ VASSERT_EQ("Value", "B: b", getFieldValue(*res));
+ }
+
+ // getAllByName function tests
+ void testFindAllFields1() {
+
+ vmime::header hdr;
+ hdr.parse("A: a1\nC: c1\n");
+
+ std::vector <vmime::shared_ptr <vmime::headerField> > res = hdr.findAllFields("B");
+
+ VASSERT_EQ("Count", static_cast <unsigned int>(0), res.size());
+ }
+
+ void testFindAllFields2() {
+
+ vmime::header hdr;
+ hdr.parse("A: a1\nB: b1\nB: b2\nC: c1\n");
+
+ std::vector <vmime::shared_ptr <vmime::headerField> > res = hdr.findAllFields("B");
+
+ VASSERT_EQ("Count", static_cast <unsigned int>(2), res.size());
+ VASSERT_EQ("First value", "B: b1", headerTest::getFieldValue(*res[0]));
+ VASSERT_EQ("Second value", "B: b2", headerTest::getFieldValue(*res[1]));
+ }
+
+ void testFindAllFields3() {
+
+ vmime::header hdr;
+ hdr.parse("A: a1\nB: b1\nB: b2\nC: c1\nC: c3\nC: c2\n");
+
+ std::vector <vmime::shared_ptr <vmime::headerField> > res = hdr.findAllFields("C");
+
+ VASSERT_EQ("Count", static_cast <unsigned int>(3), res.size());
+ VASSERT_EQ("First value", "C: c1", headerTest::getFieldValue(*res[0]));
+ VASSERT_EQ("Second value", "C: c3", headerTest::getFieldValue(*res[1]));
+ VASSERT_EQ("Second value", "C: c2", headerTest::getFieldValue(*res[2]));
+ }
+
+VMIME_TEST_SUITE_END
diff --git a/vmime-master/tests/parser/htmlTextPartTest.cpp b/vmime-master/tests/parser/htmlTextPartTest.cpp
new file mode 100644
index 0000000..6dfaaa0
--- /dev/null
+++ b/vmime-master/tests/parser/htmlTextPartTest.cpp
@@ -0,0 +1,241 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "tests/testUtils.hpp"
+#include "vmime/htmlTextPart.hpp"
+
+
+VMIME_TEST_SUITE_BEGIN(htmlTextPartTest)
+
+ VMIME_TEST_LIST_BEGIN
+ VMIME_TEST(testParseText)
+ VMIME_TEST(testParseEmbeddedObjectsCID)
+ VMIME_TEST(testParseEmbeddedObjectsLocation)
+ VMIME_TEST_LIST_END
+
+
+ static const vmime::string extractContent(
+ const vmime::shared_ptr <const vmime::contentHandler>& cth
+ ) {
+
+ std::ostringstream oss;
+ vmime::utility::outputStreamAdapter osa(oss);
+
+ cth->extract(osa);
+
+ return oss.str();
+ }
+
+
+ void testParseText() {
+
+ const vmime::string msgString = ""
+"MIME-Version: 1.0\r\n"
+"Content-Type: multipart/alternative; boundary=\"LEVEL1\"\r\n"
+"\r\n"
+"--LEVEL1\r\n"
+"Content-Type: text/plain; charset=\"x-ch1\"\r\n"
+"\r\n"
+"Plain text part\r\n"
+"--LEVEL1\r\n"
+"Content-Type: multipart/related; boundary=\"LEVEL2\"\r\n"
+"\r\n"
+"--LEVEL2\r\n"
+"Content-Type: text/html; charset=\"x-ch2\"\r\n"
+"\r\n"
+"<img src=\"cid:image@test\"/>\r\n"
+"--LEVEL2\r\n"
+"Content-Type: image/png; name=\"image.png\"\r\n"
+"Content-Disposition: inline; filename=\"image.png\"\r\n"
+"Content-ID: <image@test>\r\n"
+"\r\n"
+"Image\r\n"
+"--LEVEL2--\r\n"
+"\r\n"
+"--LEVEL1--\r\n"
+"";
+
+ vmime::shared_ptr <vmime::message> msg = vmime::make_shared <vmime::message>();
+ msg->parse(msgString);
+
+ // Sanity checks
+ VASSERT_EQ("part-count1", 2, msg->getBody()->getPartCount());
+ VASSERT_EQ("part-count2", 2, msg->getBody()->getPartAt(1)->getBody()->getPartCount());
+
+ vmime::htmlTextPart htmlPart;
+ htmlPart.parse(msg, msg->getBody()->getPartAt(1),
+ msg->getBody()->getPartAt(1)->getBody()->getPartAt(0));
+
+ VASSERT_EQ("plain", "Plain text part", extractContent(htmlPart.getPlainText()));
+ VASSERT_EQ("html", "<img src=\"cid:image@test\"/>", extractContent(htmlPart.getText()));
+
+ // Should return the charset of the HTML part
+ VASSERT_EQ("charset", "x-ch2", htmlPart.getCharset().generate());
+ }
+
+ /** Test parsing of embedded objects by CID (Content-Id).
+ */
+ void testParseEmbeddedObjectsCID() {
+
+ const vmime::string msgString = ""
+"MIME-Version: 1.0\r\n"
+"Content-Type: multipart/alternative; boundary=\"LEVEL1\"\r\n"
+"\r\n"
+"--LEVEL1\r\n"
+"Content-Type: text/plain; charset=\"x-ch1\"\r\n"
+"\r\n"
+"Plain text part\r\n"
+"--LEVEL1\r\n"
+"Content-Type: multipart/related; boundary=\"LEVEL2\"\r\n"
+"\r\n"
+"--LEVEL2\r\n" // one embedded object before...
+"Content-Type: image/png; name=\"image1.png\"\r\n"
+"Content-Disposition: inline; filename=\"image1.png\"\r\n"
+"Content-ID: <image1@test>\r\n"
+"\r\n"
+"Image1\r\n"
+"--LEVEL2\r\n" // ...the actual text part...
+"Content-Type: text/html; charset=\"x-ch2\"\r\n"
+"\r\n"
+"<img src=\"cid:image1@test\"/>\r\n"
+"<img src=\"CID:image2@test\"/>\r\n"
+"--LEVEL2\r\n" // ...and one after
+"Content-Type: image/jpeg; name=\"image2.jpg\"\r\n"
+"Content-Disposition: inline; filename=\"image2.jpg\"\r\n"
+"Content-ID: <image2@test>\r\n"
+"\r\n"
+"Image2\r\n"
+"--LEVEL2--\r\n"
+"\r\n"
+"--LEVEL1--\r\n"
+"";
+
+ vmime::shared_ptr <vmime::message> msg = vmime::make_shared <vmime::message>();
+ msg->parse(msgString);
+
+ // Sanity checks
+ VASSERT_EQ("part-count1", 2, msg->getBody()->getPartCount());
+ VASSERT_EQ("part-count2", 3, msg->getBody()->getPartAt(1)->getBody()->getPartCount());
+
+ vmime::htmlTextPart htmlPart;
+ htmlPart.parse(
+ msg, msg->getBody()->getPartAt(1),
+ msg->getBody()->getPartAt(1)->getBody()->getPartAt(1)
+ );
+
+ // Two embedded objects should be found.
+ // BUGFIX: "CID:" prefix is not case-sensitive.
+ VASSERT_EQ("count", 2, htmlPart.getObjectCount());
+
+ // Ensure the right objects have been found.
+ VASSERT_EQ("has-obj1", true, htmlPart.hasObject("image1@test"));
+ VASSERT_EQ("has-obj2", true, htmlPart.hasObject("image2@test"));
+
+ // hasObject() should also work with prefixes
+ VASSERT_EQ("has-obj1-pre", true, htmlPart.hasObject("CID:image1@test"));
+ VASSERT_EQ("has-obj2-pre", true, htmlPart.hasObject("cid:image2@test"));
+
+ // Check data in objects
+ vmime::shared_ptr <const vmime::htmlTextPart::embeddedObject> obj;
+
+ obj = htmlPart.findObject("image1@test");
+
+ VASSERT_EQ("ref-type1", vmime::htmlTextPart::embeddedObject::REFERENCED_BY_ID, obj->getReferenceType());
+ VASSERT_EQ("id-obj1", "image1@test", obj->getId());
+ VASSERT_EQ("data-obj1", "Image1", extractContent(obj->getData()));
+ VASSERT_EQ("type-obj1", "image/png", obj->getType().generate());
+
+ obj = htmlPart.findObject("image2@test");
+
+ VASSERT_EQ("ref-type2", vmime::htmlTextPart::embeddedObject::REFERENCED_BY_ID, obj->getReferenceType());
+ VASSERT_EQ("id-obj2", "image2@test", obj->getId());
+ VASSERT_EQ("data-obj2", "Image2", extractContent(obj->getData()));
+ VASSERT_EQ("type-obj2", "image/jpeg", obj->getType().generate());
+ }
+
+ /** Test parsing of embedded objects by location.
+ */
+ void testParseEmbeddedObjectsLocation() {
+
+ const vmime::string msgString = ""
+"MIME-Version: 1.0\r\n"
+"Content-Type: multipart/alternative; boundary=\"LEVEL1\"\r\n"
+"\r\n"
+"--LEVEL1\r\n"
+"Content-Type: text/plain; charset=\"x-ch1\"\r\n"
+"\r\n"
+"Plain text part\r\n"
+"--LEVEL1\r\n"
+"Content-Type: multipart/related; boundary=\"LEVEL2\"\r\n"
+"\r\n"
+"--LEVEL2\r\n"
+"Content-Type: image/png; name=\"image1.png\"\r\n"
+"Content-Location: http://www.vmime.org/test/image1.png\r\n"
+"Content-Disposition: inline; filename=\"image1.png\"\r\n"
+"Content-Id: <image1@test>\r\n"
+"\r\n"
+"Image1\r\n"
+"--LEVEL2\r\n"
+"Content-Type: text/html; charset=\"x-ch2\"\r\n"
+"\r\n"
+"<img src=\"http://www.vmime.org/test/image1.png\"/>\r\n"
+"--LEVEL2--\r\n"
+"\r\n"
+"--LEVEL1--\r\n"
+"";
+
+ vmime::shared_ptr <vmime::message> msg = vmime::make_shared <vmime::message>();
+ msg->parse(msgString);
+
+ // Sanity checks
+ VASSERT_EQ("part-count1", 2, msg->getBody()->getPartCount());
+ VASSERT_EQ("part-count2", 2, msg->getBody()->getPartAt(1)->getBody()->getPartCount());
+
+ vmime::htmlTextPart htmlPart;
+ htmlPart.parse(
+ msg, msg->getBody()->getPartAt(1),
+ msg->getBody()->getPartAt(1)->getBody()->getPartAt(1)
+ );
+
+ // Only one embedded object
+ VASSERT_EQ("count", 1, htmlPart.getObjectCount());
+
+ // Should work only with Content-Location as the Content-Id is
+ // not referenced in the HTML contents
+ VASSERT_EQ("has-obj-loc", true, htmlPart.hasObject("http://www.vmime.org/test/image1.png"));
+ VASSERT_EQ("has-obj-cid", false, htmlPart.hasObject("image1@test"));
+
+ // Check data
+ vmime::shared_ptr <const vmime::htmlTextPart::embeddedObject> obj;
+
+ obj = htmlPart.findObject("http://www.vmime.org/test/image1.png");
+
+ VASSERT_EQ("ref-type", vmime::htmlTextPart::embeddedObject::REFERENCED_BY_LOCATION, obj->getReferenceType());
+ VASSERT_EQ("id-obj", "http://www.vmime.org/test/image1.png", obj->getId());
+ VASSERT_EQ("data-obj", "Image1", extractContent(obj->getData()));
+ VASSERT_EQ("type-obj", "image/png", obj->getType().generate());
+ }
+
+ // TODO: test generation of text parts
+
+VMIME_TEST_SUITE_END
diff --git a/vmime-master/tests/parser/mailboxGroupTest.cpp b/vmime-master/tests/parser/mailboxGroupTest.cpp
new file mode 100644
index 0000000..18ff425
--- /dev/null
+++ b/vmime-master/tests/parser/mailboxGroupTest.cpp
@@ -0,0 +1,107 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "tests/testUtils.hpp"
+
+
+VMIME_TEST_SUITE_BEGIN(mailboxGroupTest)
+
+ VMIME_TEST_LIST_BEGIN
+ VMIME_TEST(testParseExtraWhitespaces)
+ VMIME_TEST(testParseNoEndDelimiter)
+ VMIME_TEST(testParseExtraChars)
+ VMIME_TEST(testEmptyGroup)
+ VMIME_TEST(testEncodedEmptyGroup)
+ VMIME_TEST_LIST_END
+
+
+ void testParseExtraWhitespaces() {
+
+ vmime::mailboxGroup mgrp;
+ mgrp.parse(" \t group : aaa <aaa@vmime.org>, bbb <bbb@vmime.org>");
+
+ VASSERT_EQ("name", "group", mgrp.getName().getWholeBuffer());
+ VASSERT_EQ("count", 2, mgrp.getMailboxCount());
+
+ VASSERT_EQ("mbox1.email", "aaa@vmime.org", mgrp.getMailboxAt(0)->getEmail());
+ VASSERT_EQ("mbox1.name", "aaa", mgrp.getMailboxAt(0)->getName());
+
+ VASSERT_EQ("mbox2.email", "bbb@vmime.org", mgrp.getMailboxAt(1)->getEmail());
+ VASSERT_EQ("mbox2.name", "bbb", mgrp.getMailboxAt(1)->getName());
+ }
+
+ void testParseNoEndDelimiter() {
+
+ vmime::addressList addrs;
+ addrs.parse("group: aaa <aaa@vmime.org>, bbb <bbb@vmime.org>");
+
+ VASSERT_EQ("count", 1, addrs.getAddressCount());
+ VASSERT_TRUE("is group", addrs.getAddressAt(0)->isGroup());
+
+ vmime::shared_ptr <vmime::mailboxGroup> mgrp =
+ vmime::dynamicCast <vmime::mailboxGroup>(addrs.getAddressAt(0));
+
+ VASSERT_EQ("name", "group", mgrp->getName().getWholeBuffer());
+ VASSERT_EQ("count", 2, mgrp->getMailboxCount());
+
+ VASSERT_EQ("mbox1.email", "aaa@vmime.org", mgrp->getMailboxAt(0)->getEmail());
+ VASSERT_EQ("mbox1.name", "aaa", mgrp->getMailboxAt(0)->getName());
+
+ VASSERT_EQ("mbox2.email", "bbb@vmime.org", mgrp->getMailboxAt(1)->getEmail());
+ VASSERT_EQ("mbox2.name", "bbb", mgrp->getMailboxAt(1)->getName());
+ }
+
+ void testParseExtraChars() {
+
+ vmime::mailboxGroup mgrp;
+ mgrp.parse("group: aaa <aaa@vmime.org>, bbb <bbb@vmime.org>; extra chars here...");
+
+ VASSERT_EQ("name", "group", mgrp.getName().getWholeBuffer());
+ VASSERT_EQ("count", 2, mgrp.getMailboxCount());
+
+ VASSERT_EQ("mbox1.email", "aaa@vmime.org", mgrp.getMailboxAt(0)->getEmail());
+ VASSERT_EQ("mbox1.name", "aaa", mgrp.getMailboxAt(0)->getName());
+
+ VASSERT_EQ("mbox2.email", "bbb@vmime.org", mgrp.getMailboxAt(1)->getEmail());
+ VASSERT_EQ("mbox2.name", "bbb", mgrp.getMailboxAt(1)->getName());
+ }
+
+ void testEmptyGroup() {
+
+ vmime::mailboxGroup mgrp;
+ mgrp.parse("Undisclosed recipients:;");
+
+ VASSERT_EQ("name", "Undisclosed recipients", mgrp.getName().getWholeBuffer());
+ VASSERT_EQ("count", 0, mgrp.getMailboxCount());
+ }
+
+ void testEncodedEmptyGroup() {
+
+ vmime::mailboxGroup mgrp;
+ mgrp.parse("=?us-ascii?Q?Undisclosed_recipients?=:;");
+
+ VASSERT_EQ("name", "Undisclosed recipients", mgrp.getName().getWholeBuffer());
+ VASSERT_EQ("count", 0, mgrp.getMailboxCount());
+ }
+
+VMIME_TEST_SUITE_END
diff --git a/vmime-master/tests/parser/mailboxListTest.cpp b/vmime-master/tests/parser/mailboxListTest.cpp
new file mode 100644
index 0000000..7505acd
--- /dev/null
+++ b/vmime-master/tests/parser/mailboxListTest.cpp
@@ -0,0 +1,47 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "tests/testUtils.hpp"
+
+
+VMIME_TEST_SUITE_BEGIN(mailboxListTest)
+
+ VMIME_TEST_LIST_BEGIN
+ VMIME_TEST(testParseGroup)
+ VMIME_TEST_LIST_END
+
+
+ // Disposition-Notification-To:: <email@domain.com>
+ void testParseGroup() {
+
+ // Groups should be extracted to multiple mailboxes in mailbox lists
+ vmime::mailboxList mboxList;
+ mboxList.parse("email1@domain1.com, : <email2@domain2.com>, email3@domain3.com");
+
+ VASSERT_EQ("count", 3, mboxList.getMailboxCount());
+ VASSERT_EQ("email", "email1@domain1.com", mboxList.getMailboxAt(0)->getEmail().generate());
+ VASSERT_EQ("email", "email2@domain2.com", mboxList.getMailboxAt(1)->getEmail().generate());
+ VASSERT_EQ("email", "email3@domain3.com", mboxList.getMailboxAt(2)->getEmail().generate());
+ }
+
+VMIME_TEST_SUITE_END
diff --git a/vmime-master/tests/parser/mailboxTest.cpp b/vmime-master/tests/parser/mailboxTest.cpp
new file mode 100644
index 0000000..997a6a3
--- /dev/null
+++ b/vmime-master/tests/parser/mailboxTest.cpp
@@ -0,0 +1,187 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "tests/testUtils.hpp"
+
+
+VMIME_TEST_SUITE_BEGIN(mailboxTest)
+
+ VMIME_TEST_LIST_BEGIN
+ VMIME_TEST(testParse)
+ VMIME_TEST(testEmptyEmailAddress)
+ VMIME_TEST(testSeparatorInComment)
+ VMIME_TEST(testMalformations)
+ VMIME_TEST(testExcessiveQuoting)
+ VMIME_TEST_LIST_END
+
+
+ void testParse() {
+
+ static const vmime::string testSuitesParse[] = {
+
+ // Test 1
+ "My (this is a comment)name <me(another \\)comment) @ somewhere(else).com>",
+
+ "[address-list: [[mailbox: name=[text: [[word: charset=us-ascii, buffer=My name]]], email=me@somewhere.com]]]",
+
+ // Test 2
+ "mailbox1 <mailbox@one>,;,,, ,, ,,;group1:mailbox1@group1, mailbox2@group2,,\"mailbox #3\" <mailbox3@group2>;, <mailbox@two>,,,,,,,,=?iso-8859-1?q?mailbox_number_3?= <mailbox@three>, =?abc?Q?mailbox?= =?def?Q?_number_4?= <mailbox@four>",
+
+ "[address-list: [[mailbox: name=[text: [[word: charset=us-ascii, buffer=mailbox1]]], email=mailbox@one],[mailbox-group: name=[text: [[word: charset=us-ascii, buffer=group1]]], list=[[mailbox: name=[text: []], email=mailbox1@group1],[mailbox: name=[text: []], email=mailbox2@group2],[mailbox: name=[text: [[word: charset=us-ascii, buffer=mailbox #3]]], email=mailbox3@group2]]],[mailbox: name=[text: []], email=mailbox@two],[mailbox: name=[text: [[word: charset=iso-8859-1, buffer=mailbox number 3]]], email=mailbox@three],[mailbox: name=[text: [[word: charset=abc, buffer=mailbox],[word: charset=def, buffer= number 4]]], email=mailbox@four]]]",
+
+ // Test 3
+ "John Doe <john.doe@acme.com>",
+
+ "[address-list: [[mailbox: name=[text: [[word: charset=us-ascii, buffer=John Doe]]], email=john.doe@acme.com]]]",
+
+ // Test 4
+ "john.doe@acme.com (John Doe)",
+
+ "[address-list: [[mailbox: name=[text: []], email=john.doe@acme.com]]]",
+
+ // Test 5
+ "John.Doe(ignore)@acme.com (John Doe)",
+
+ "[address-list: [[mailbox: name=[text: []], email=John.Doe@acme.com]]]",
+
+ // Test 6
+ "<john.doe@acme.com>",
+
+ "[address-list: [[mailbox: name=[text: []], email=john.doe@acme.com]]]",
+
+ // Test 7
+ "john.doe@acme.com",
+
+ "[address-list: [[mailbox: name=[text: []], email=john.doe@acme.com]]]",
+
+ // Test 8
+ "\"John Doe\" <john.doe@acme.com>",
+
+ "[address-list: [[mailbox: name=[text: [[word: charset=us-ascii, buffer=John Doe]]], email=john.doe@acme.com]]]",
+
+ // Test 9
+ "=?us-ascii?q?John?=<john.doe@acme.com>",
+
+ "[address-list: [[mailbox: name=[text: [[word: charset=us-ascii, buffer=John]]], email=john.doe@acme.com]]]",
+
+ // Test 10
+ "\"John\"<john.doe@acme.com>",
+
+ "[address-list: [[mailbox: name=[text: [[word: charset=us-ascii, buffer=John]]], email=john.doe@acme.com]]]",
+
+ // Test 11
+ "John<john.doe@acme.com>",
+
+ "[address-list: [[mailbox: name=[text: [[word: charset=us-ascii, buffer=John]]], email=john.doe@acme.com]]]"
+ };
+
+ for (unsigned int i = 0 ; i < sizeof(testSuitesParse) / sizeof(testSuitesParse[0]) / 2 ; ++i) {
+
+ vmime::string in = testSuitesParse[i * 2];
+ vmime::string out = testSuitesParse[i * 2 + 1];
+
+ std::ostringstream oss;
+ oss << "Test " << (i + 1);
+
+ vmime::addressList addrList;
+ addrList.parse(in);
+
+ std::ostringstream cmp;
+ cmp << addrList;
+
+ VASSERT_EQ(oss.str(), out, cmp.str());
+ }
+ }
+
+ void testEmptyEmailAddress() {
+
+ vmime::addressList addrList;
+ addrList.parse("\"Full Name\" <>");
+
+ VASSERT_EQ("count", 1, addrList.getAddressCount());
+ VASSERT_EQ("!group", false, addrList.getAddressAt(0)->isGroup());
+
+ vmime::shared_ptr <vmime::mailbox> mbox =
+ vmime::dynamicCast <vmime::mailbox>(addrList.getAddressAt(0));
+
+ VASSERT_EQ("name", "Full Name", mbox->getName());
+ VASSERT_EQ("email", "", mbox->getEmail());
+ }
+
+ void testSeparatorInComment() {
+
+ vmime::addressList addrList;
+ addrList.parse("aaa(comment,comment)@vmime.org, bbb@vmime.org");
+
+ VASSERT_EQ("count", 2, addrList.getAddressCount());
+
+ vmime::shared_ptr <vmime::mailbox> mbox1 =
+ vmime::dynamicCast <vmime::mailbox>(addrList.getAddressAt(0));
+ vmime::shared_ptr <vmime::mailbox> mbox2 =
+ vmime::dynamicCast <vmime::mailbox>(addrList.getAddressAt(1));
+
+ VASSERT_EQ("name1", vmime::text(), mbox1->getName());
+ VASSERT_EQ("email1", "aaa@vmime.org", mbox1->getEmail());
+
+ VASSERT_EQ("name2", vmime::text(), mbox2->getName());
+ VASSERT_EQ("email2", "bbb@vmime.org", mbox2->getEmail());
+ }
+
+ void testMalformations() {
+ vmime::mailbox mbox;
+
+ mbox.parse("a@b.c <e@f.g>");
+ VASSERT_EQ("name", vmime::text("a@b.c"), mbox.getName());
+ VASSERT_EQ("email", "e@f.g", mbox.getEmail());
+
+ mbox.parse("a@b.c e@f.g <h@i.j>");
+ VASSERT_EQ("name", vmime::text("a@b.c e@f.g"), mbox.getName());
+ VASSERT_EQ("email", "h@i.j", mbox.getEmail());
+
+ mbox.parse("Foo <bar<baz@quux.com>");
+ VASSERT_EQ("name", vmime::text("Foo <bar"), mbox.getName());
+ VASSERT_EQ("email", "baz@quux.com", mbox.getEmail());
+
+ mbox.parse("Foo <foo@x.com> <bar@x.com>");
+ VASSERT_EQ("name", vmime::text("Foo <foo@x.com>"), mbox.getName());
+ VASSERT_EQ("email", "bar@x.com", mbox.getEmail());
+
+ mbox.parse("Foo <foo@x.com> Bar <bar@y.com>");
+ VASSERT_EQ("name", vmime::text("Foo <foo@x.com> Bar"), mbox.getName());
+ VASSERT_EQ("email", "bar@y.com", mbox.getEmail());
+ }
+
+ void testExcessiveQuoting() {
+ using namespace vmime;
+
+ // Check that ASCII display names are not encoded more than necessary
+ emailAddress e("a@b.com");
+ auto a = make_shared<mailbox>(text(word("Foo B@r", charsets::US_ASCII)), e);
+ VASSERT_EQ("generate", "\"Foo B@r\" <a@b.com>", a->generate());
+ VASSERT_NEQ("generate", "=?utf-8?Q?Foo_B=40r?= <a@b.com>", a->generate());
+
+ a = make_shared<mailbox>(text(word("Foo B@r", charsets::UTF_8)), e);
+ VASSERT_EQ("generate", "=?utf-8?Q?Foo_B=40r?= <a@b.com>", a->generate());
+ }
+
+VMIME_TEST_SUITE_END
diff --git a/vmime-master/tests/parser/mediaTypeTest.cpp b/vmime-master/tests/parser/mediaTypeTest.cpp
new file mode 100644
index 0000000..e98cfcd
--- /dev/null
+++ b/vmime-master/tests/parser/mediaTypeTest.cpp
@@ -0,0 +1,100 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "tests/testUtils.hpp"
+
+
+VMIME_TEST_SUITE_BEGIN(mediaTypeTest)
+
+ VMIME_TEST_LIST_BEGIN
+ VMIME_TEST(testConstructors)
+ VMIME_TEST(testCopy)
+ VMIME_TEST(testSetFromString)
+ VMIME_TEST(testParse)
+ VMIME_TEST(testGenerate)
+ VMIME_TEST_LIST_END
+
+
+ void testConstructors() {
+
+ vmime::mediaType t1;
+
+ VASSERT_EQ("1.1", vmime::mediaTypes::APPLICATION, t1.getType());
+ VASSERT_EQ("1.2", vmime::mediaTypes::APPLICATION_OCTET_STREAM, t1.getSubType());
+
+ vmime::mediaType t2("type", "sub");
+
+ VASSERT_EQ("2.1", "type", t2.getType());
+ VASSERT_EQ("2.2", "sub", t2.getSubType());
+
+ vmime::mediaType t3("type/sub");
+
+ VASSERT_EQ("3.1", "type", t3.getType());
+ VASSERT_EQ("3.2", "sub", t3.getSubType());
+ }
+
+ void testCopy() {
+
+ vmime::mediaType t1("type/sub");
+
+ VASSERT_EQ("eq1", "type", t1.getType());
+ VASSERT_EQ("eq2", "sub", t1.getSubType());
+
+ VASSERT("operator==", t1 == t1);
+ VASSERT("clone", t1 == *vmime::clone(t1));
+
+ VASSERT_EQ("eq3", "type", vmime::clone(t1)->getType());
+ VASSERT_EQ("eq4", "sub", vmime::clone(t1)->getSubType());
+
+ vmime::mediaType t2;
+ t2.copyFrom(t1);
+
+ VASSERT("copyFrom", t1 == t2);
+ }
+
+ void testSetFromString() {
+
+ vmime::mediaType t1;
+ t1.setFromString("type/sub");
+
+ VASSERT_EQ("1.1", "type", t1.getType());
+ VASSERT_EQ("1.2", "sub", t1.getSubType());
+ }
+
+ void testParse() {
+
+ vmime::mediaType t1;
+ t1.parse("type/sub");
+
+ VASSERT_EQ("1.1", "type", t1.getType());
+ VASSERT_EQ("1.2", "sub", t1.getSubType());
+ }
+
+ void testGenerate() {
+
+ vmime::mediaType t1("type", "sub");
+
+ VASSERT_EQ("1", "type/sub", t1.generate());
+ }
+
+VMIME_TEST_SUITE_END
diff --git a/vmime-master/tests/parser/messageIdSequenceTest.cpp b/vmime-master/tests/parser/messageIdSequenceTest.cpp
new file mode 100644
index 0000000..0237108
--- /dev/null
+++ b/vmime-master/tests/parser/messageIdSequenceTest.cpp
@@ -0,0 +1,78 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "tests/testUtils.hpp"
+
+
+VMIME_TEST_SUITE_BEGIN(messageIdSequenceTest)
+
+ VMIME_TEST_LIST_BEGIN
+ VMIME_TEST(testParse)
+ VMIME_TEST(testGenerate)
+ VMIME_TEST_LIST_END
+
+
+ void testParse() {
+
+ vmime::messageIdSequence s1;
+ s1.parse("");
+
+ VASSERT_EQ("1", 0, s1.getMessageIdCount());
+
+ vmime::messageIdSequence s2;
+ s2.parse(" \t ");
+
+ VASSERT_EQ("2", 0, s2.getMessageIdCount());
+
+ vmime::messageIdSequence s3;
+ s3.parse("<a@b>");
+
+ VASSERT_EQ("3.1", 1, s3.getMessageIdCount());
+ VASSERT_EQ("3.2", "a", s3.getMessageIdAt(0)->getLeft());
+ VASSERT_EQ("3.3", "b", s3.getMessageIdAt(0)->getRight());
+
+ vmime::messageIdSequence s4;
+ s4.parse("<a@b> \r\n\t<c@d>");
+
+ VASSERT_EQ("4.1", 2, s4.getMessageIdCount());
+ VASSERT_EQ("4.2", "a", s4.getMessageIdAt(0)->getLeft());
+ VASSERT_EQ("4.3", "b", s4.getMessageIdAt(0)->getRight());
+ VASSERT_EQ("4.4", "c", s4.getMessageIdAt(1)->getLeft());
+ VASSERT_EQ("4.5", "d", s4.getMessageIdAt(1)->getRight());
+ }
+
+ void testGenerate() {
+
+ vmime::messageIdSequence s1;
+ s1.appendMessageId(vmime::make_shared <vmime::messageId>("a", "b"));
+
+ VASSERT_EQ("1", "<a@b>", s1.generate());
+
+ vmime::messageIdSequence s2;
+ s2.appendMessageId(vmime::make_shared <vmime::messageId>("a", "b"));
+ s2.appendMessageId(vmime::make_shared <vmime::messageId>("c", "d"));
+
+ VASSERT_EQ("2", "<a@b> <c@d>", s2.generate());
+ }
+
+VMIME_TEST_SUITE_END
diff --git a/vmime-master/tests/parser/messageIdTest.cpp b/vmime-master/tests/parser/messageIdTest.cpp
new file mode 100644
index 0000000..8433093
--- /dev/null
+++ b/vmime-master/tests/parser/messageIdTest.cpp
@@ -0,0 +1,77 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "tests/testUtils.hpp"
+
+
+VMIME_TEST_SUITE_BEGIN(messageIdTest)
+
+ VMIME_TEST_LIST_BEGIN
+ VMIME_TEST(testParse)
+ VMIME_TEST(testParseInvalid)
+ VMIME_TEST(testGenerate)
+ VMIME_TEST_LIST_END
+
+
+ void testParse() {
+
+ vmime::messageId m1;
+ m1.parse("<a@b>");
+
+ VASSERT_EQ("1.1", "a", m1.getLeft());
+ VASSERT_EQ("1.2", "b", m1.getRight());
+ }
+
+ void testParseInvalid() {
+
+ vmime::messageId m1;
+ m1.parse("foo@bar");
+
+ VASSERT_EQ("1.1", "foo", m1.getLeft());
+ VASSERT_EQ("1.2", "bar", m1.getRight());
+ }
+
+ void testGenerate() {
+
+ vmime::messageId m1;
+
+ VASSERT_EQ("1", "<>", m1.generate());
+
+ vmime::messageId m2;
+ m2.setLeft("a");
+
+ VASSERT_EQ("2", "<a>", m2.generate());
+
+ vmime::messageId m3;
+ m3.setRight("b");
+
+ VASSERT_EQ("3", "<@b>", m3.generate());
+
+ vmime::messageId m4;
+ m4.setLeft("a");
+ m4.setRight("b");
+
+ VASSERT_EQ("4", "<a@b>", m4.generate());
+ }
+
+VMIME_TEST_SUITE_END
diff --git a/vmime-master/tests/parser/messageTest.cpp b/vmime-master/tests/parser/messageTest.cpp
new file mode 100644
index 0000000..b89d63e
--- /dev/null
+++ b/vmime-master/tests/parser/messageTest.cpp
@@ -0,0 +1,64 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "tests/testUtils.hpp"
+
+
+VMIME_TEST_SUITE_BEGIN(messageTest)
+
+ VMIME_TEST_LIST_BEGIN
+ VMIME_TEST(testGetGeneratedSize)
+ VMIME_TEST_LIST_END
+
+
+ void testGetGeneratedSize() {
+
+ vmime::generationContext ctx;
+
+ vmime::shared_ptr <vmime::message> msg = vmime::make_shared <vmime::message>();
+ msg->getHeader()->getField("Foo")->setValue(vmime::string("bar"));
+
+ vmime::htmlTextPart textPart;
+ textPart.setPlainText(
+ vmime::make_shared <vmime::stringContentHandler>(
+ "Foo bar bazé foo foo foo"
+ )
+ );
+ textPart.setText(
+ vmime::make_shared <vmime::stringContentHandler>(
+ "Foo bar <strong>bazé</strong> foo foo foo"
+ )
+ );
+ textPart.generateIn(msg, msg);
+
+ // Estimated/computed generated size must be greater than the actual generated size
+ const vmime::size_t genSize = msg->getGeneratedSize(ctx);
+ const vmime::size_t actualSize = msg->generate().length();
+
+ std::ostringstream oss;
+ oss << "estimated size (" << genSize << ") >= actual size (" << actualSize << ")";
+
+ VASSERT(oss.str(), genSize >= actualSize);
+ }
+
+VMIME_TEST_SUITE_END
diff --git a/vmime-master/tests/parser/parameterTest.cpp b/vmime-master/tests/parser/parameterTest.cpp
new file mode 100644
index 0000000..464c305
--- /dev/null
+++ b/vmime-master/tests/parser/parameterTest.cpp
@@ -0,0 +1,722 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "tests/testUtils.hpp"
+
+#include <locale>
+#include <clocale>
+
+
+VMIME_TEST_SUITE_BEGIN(parameterTest)
+
+ VMIME_TEST_LIST_BEGIN
+ VMIME_TEST(testParse)
+ VMIME_TEST(testParseRFC2231)
+ VMIME_TEST(testGenerate)
+ VMIME_TEST(testGetGeneratedSize)
+ VMIME_TEST(testGenerateRFC2231)
+ VMIME_TEST(testGetGeneratedSizeRFC2231)
+ VMIME_TEST(testNonStandardEncodedParam)
+ VMIME_TEST(testParseNonSignificantWS)
+ VMIME_TEST(testEncodeTSpecials)
+ VMIME_TEST(testEncodeTSpecialsInRFC2231)
+ VMIME_TEST(testWhitespaceBreaksTheValue)
+ VMIME_TEST_LIST_END
+
+
+ // HACK: parameterizedHeaderField constructor is private
+ class parameterizedHeaderField : public vmime::parameterizedHeaderField {
+
+ public:
+
+ parameterizedHeaderField() {
+
+ setName("F");
+ setValue(vmime::headerFieldFactory::getInstance()->createValue(getName()));
+ setValue(vmime::word("X"));
+ }
+
+ using vmime::parameterizedHeaderField::generate;
+
+ const vmime::string generate(
+ const vmime::generationContext::EncodedParameterValueModes genMode,
+ const vmime::size_t maxLineLength = 0
+ ) const {
+
+ vmime::generationContext ctx(vmime::generationContext::getDefaultContext());
+ ctx.setEncodedParameterValueMode(genMode);
+
+ if (maxLineLength != 0) {
+ ctx.setMaxLineLength(maxLineLength);
+ }
+
+ std::ostringstream oss;
+ vmime::utility::outputStreamAdapter adapter(oss);
+
+ vmime::parameterizedHeaderField::generate(ctx, adapter);
+
+ return oss.str();
+ }
+ };
+
+
+ const vmime::string generateParameter(
+ const vmime::parameter& param,
+ const vmime::generationContext& ctx,
+ const vmime::size_t maxLineLength = 0
+ ) const {
+
+ vmime::generationContext ctx2(ctx);
+
+ if (maxLineLength != 0) {
+ ctx2.setMaxLineLength(maxLineLength);
+ }
+
+ std::ostringstream oss;
+ vmime::utility::outputStreamAdapter adapter(oss);
+
+ param.generate(ctx2, adapter);
+
+ return oss.str();
+ }
+
+
+#define FIELD_VALUE(f) (f.getValue()->generate())
+#define PARAM_VALUE(p, n) (p.getParameterAt(n)->getValue().generate())
+#define PARAM_NAME(p, n) (p.getParameterAt(n)->getName())
+#define PARAM_CHARSET(p, n) \
+ (p.getParameterAt(n)->getValue().getCharset().generate())
+#define PARAM_LANG(p, n) \
+ (p.getParameterAt(n)->getValue().getLanguage())
+#define PARAM_BUFFER(p, n) \
+ (p.getParameterAt(n)->getValue().getBuffer())
+
+
+ void setUp() {
+
+ // Set the global C and C++ locale to the user-configured locale.
+ // The locale should use UTF-8 encoding for these tests to run successfully.
+ try {
+ std::locale::global(std::locale(""));
+ } catch (std::exception &) {
+ std::setlocale(LC_ALL, "");
+ }
+ }
+
+ void tearDown() {
+
+ // Restore default locale
+ std::locale::global(std::locale("C"));
+ }
+
+
+ void testParse() {
+
+ // Simple parameter
+ parameterizedHeaderField p1;
+ p1.parse("X; param1=value1;\r\n");
+
+ VASSERT_EQ("1.1", 1, p1.getParameterCount());
+ VASSERT_EQ("1.2", "param1", PARAM_NAME(p1, 0));
+ VASSERT_EQ("1.3", "value1", PARAM_VALUE(p1, 0));
+
+ // Multi-section parameters (1/2)
+ parameterizedHeaderField p2a;
+ p2a.parse(
+ "X; param1=value1;\r\n"
+ " param2*0=\"val\";\r\n"
+ " param2*1=\"ue2\";"
+ );
+
+ VASSERT_EQ("2a.1", 2, p2a.getParameterCount());
+ VASSERT_EQ("2a.2", "param1", PARAM_NAME(p2a, 0));
+ VASSERT_EQ("2a.3", "value1", PARAM_VALUE(p2a, 0));
+ VASSERT_EQ("2a.4", "param2", PARAM_NAME(p2a, 1));
+ VASSERT_EQ("2a.5", "value2", PARAM_VALUE(p2a, 1));
+
+ // Multi-section parameters (2/2)
+ parameterizedHeaderField p2b;
+ p2b.parse(
+ "X; param1=value1;\r\n"
+ " param2=\"should be ignored\";\r\n"
+ " param2*0=\"val\";\r\n"
+ " param2*1=\"ue2\";"
+ );
+
+ VASSERT_EQ("2b.1", 2, p2b.getParameterCount());
+ VASSERT_EQ("2b.2", "param1", PARAM_NAME(p2b, 0));
+ VASSERT_EQ("2b.3", "value1", PARAM_VALUE(p2b, 0));
+ VASSERT_EQ("2b.4", "param2", PARAM_NAME(p2b, 1));
+ VASSERT_EQ("2b.5", "value2", PARAM_VALUE(p2b, 1));
+
+ // Extended parameter (charset and language information)
+ parameterizedHeaderField p3;
+ p3.parse("X; param1*=charset'language'value1;\r\n");
+
+ VASSERT_EQ("3.1", 1, p3.getParameterCount());
+ VASSERT_EQ("3.2", "param1", PARAM_NAME(p3, 0));
+ VASSERT_EQ("3.3", "charset", PARAM_CHARSET(p3, 0));
+ VASSERT_EQ("3.4", "value1", PARAM_BUFFER(p3, 0));
+
+ // Encoded characters in extended parameter values
+ parameterizedHeaderField p4;
+ p4.parse("X; param1*=a%20value%20with%20multiple%20word%73"); // 0x73 = 's'
+
+ VASSERT_EQ("4.1", 1, p4.getParameterCount());
+ VASSERT_EQ("4.2", "param1", PARAM_NAME(p4, 0));
+ VASSERT_EQ("4.3", "a value with multiple words", PARAM_VALUE(p4, 0));
+
+ // Invalid encoded character
+ parameterizedHeaderField p5;
+ p5.parse("X; param1*=test%20value%");
+
+ VASSERT_EQ("5.1", 1, p5.getParameterCount());
+ VASSERT_EQ("5.2", "param1", PARAM_NAME(p5, 0));
+ VASSERT_EQ("5.3", "test value%", PARAM_VALUE(p5, 0));
+
+ // Spaces before and after '='
+ parameterizedHeaderField p6;
+ p6.parse("X; param1\t= \"value1\"");
+
+ VASSERT_EQ("6.1", 1, p6.getParameterCount());
+ VASSERT_EQ("6.2", "param1", PARAM_NAME(p6, 0));
+ VASSERT_EQ("6.3", "value1", PARAM_VALUE(p6, 0));
+
+ // Quoted strings and escaped chars
+ parameterizedHeaderField p7;
+ p7.parse("X; param1=\"this is a slash: \\\"\\\\\\\"\""); // \"\\\"
+
+ VASSERT_EQ("7.1", 1, p7.getParameterCount());
+ VASSERT_EQ("7.2", "param1", PARAM_NAME(p7, 0));
+ VASSERT_EQ("7.3", "this is a slash: \"\\\"", PARAM_VALUE(p7, 0));
+ }
+
+ void testParseRFC2231() {
+
+ // Extended parameter with charset specified in more than one
+ // section (this is forbidden by RFC, but is should not fail)
+ parameterizedHeaderField p1;
+ p1.parse(
+ "X; param1*0*=charset1'language1'value1;\r\n"
+ " param1*1*=charset2'language2'value2;"
+ );
+
+ VASSERT_EQ("1.1", 1, p1.getParameterCount());
+ VASSERT_EQ("1.2", "param1", PARAM_NAME(p1, 0));
+ VASSERT_EQ("1.3", "charset1", PARAM_CHARSET(p1, 0));
+ VASSERT_EQ("1.4", "value1charset2'language2'value2", PARAM_BUFFER(p1, 0));
+
+ // Charset not specified in the first section (that is not encoded),
+ // but specified in the second one (legal)
+ parameterizedHeaderField p2;
+ p2.parse(
+ "X; param1*0=value1;\r\n"
+ " param1*1*=charset'language'value2;"
+ );
+
+ VASSERT_EQ("2.1", 1, p2.getParameterCount());
+ VASSERT_EQ("2.2", "param1", PARAM_NAME(p2, 0));
+ VASSERT_EQ("2.3", "charset", PARAM_CHARSET(p2, 0));
+ VASSERT_EQ("2.4", "value1value2", PARAM_BUFFER(p2, 0));
+
+ // Characters prefixed with '%' in a simple (not extended) section
+ // should not be decoded
+ parameterizedHeaderField p3;
+ p3.parse("X; param1=val%20ue1");
+
+ VASSERT_EQ("3.1", 1, p3.getParameterCount());
+ VASSERT_EQ("3.2", "param1", PARAM_NAME(p3, 0));
+ VASSERT_EQ("3.3", "val%20ue1", PARAM_VALUE(p3, 0));
+
+ // Multiple sections + charset specified and encoding
+ parameterizedHeaderField p4;
+ p4.parse(
+ "X; param1*0*=charset'language'value1a%20;"
+ " param1*1*=value1b%20;"
+ " param1*2=value1c"
+ );
+
+ VASSERT_EQ("4.1", 1, p4.getParameterCount());
+ VASSERT_EQ("4.2", "param1", PARAM_NAME(p4, 0));
+ VASSERT_EQ("4.3", "charset", PARAM_CHARSET(p4, 0));
+ VASSERT_EQ("4.4", "value1a value1b value1c", PARAM_BUFFER(p4, 0));
+
+ // No charset specified: defaults to US-ASCII
+ parameterizedHeaderField p5;
+ p5.parse("X; param1*='language'value1");
+
+ VASSERT_EQ("5.1", 1, p5.getParameterCount());
+ VASSERT_EQ("5.2", "param1", PARAM_NAME(p5, 0));
+ VASSERT_EQ("5.3", "us-ascii", PARAM_CHARSET(p5, 0));
+ VASSERT_EQ("5.4", "value1", PARAM_BUFFER(p5, 0));
+
+ // Language specification
+ parameterizedHeaderField p6;
+ p6.parse("X; param1*=us-ascii'en-us'This%20is%20%2A%2A%2Afun%2A%2A%2A");
+
+ VASSERT_EQ("6.1", 1, p6.getParameterCount());
+ VASSERT_EQ("6.2", "param1", PARAM_NAME(p6, 0));
+ VASSERT_EQ("6.3", "us-ascii", PARAM_CHARSET(p6, 0));
+ VASSERT_EQ("6.4", "en-us", PARAM_LANG(p6, 0));
+ VASSERT_EQ("6.5", "This is ***fun***", PARAM_BUFFER(p6, 0));
+ }
+
+ void testGenerate() {
+
+ // Simple parameter/value
+ parameterizedHeaderField p1;
+ p1.appendParameter(vmime::make_shared <vmime::parameter>("param1", "value1"));
+
+ VASSERT_EQ("1", "F: X; param1=value1", p1.generate());
+
+ // Value that needs quoting (1/2)
+ parameterizedHeaderField p2a;
+ p2a.appendParameter(vmime::make_shared <vmime::parameter>("param1", "value1a;value1b"));
+
+ VASSERT_EQ("2a", "F: X; param1=\"value1a;value1b\"", p2a.generate());
+
+ // Value that needs quoting (2/2)
+ parameterizedHeaderField p2b;
+ p2b.appendParameter(vmime::make_shared <vmime::parameter>("param1", "va\\lue\"1"));
+
+ VASSERT_EQ("2b", "F: X; param1=\"va\\\\lue\\\"1\"", p2b.generate());
+ }
+
+ void testGetGeneratedSize() {
+
+ vmime::generationContext ctx(vmime::generationContext::getDefaultContext());
+
+ vmime::parameter p1("param1", "value1");
+ VASSERT("1", p1.getGeneratedSize(ctx) >= generateParameter(p1, ctx).length());
+
+ vmime::parameter p2a("param1", "value1a;value1b");
+ VASSERT("2&", p2a.getGeneratedSize(ctx) >= generateParameter(p2a, ctx).length());
+
+ vmime::parameter p2b("param1", "va\\lue\"1");
+ VASSERT("1", p2b.getGeneratedSize(ctx) >= generateParameter(p2b, ctx).length());
+ }
+
+ void testGenerateRFC2231() {
+
+ // Extended parameter with charset specifier
+ parameterizedHeaderField p1;
+ p1.appendParameter(
+ vmime::make_shared <vmime::parameter>(
+ "param1",
+ vmime::word("value 1\xe9", vmime::charset("charset"))
+ )
+ );
+
+ VASSERT_EQ(
+ "1.no-encoding",
+ "F: X; param1=\"value 1\"",
+ p1.generate(vmime::generationContext::PARAMETER_VALUE_NO_ENCODING)
+ );
+
+ VASSERT_EQ(
+ "1.rfc2047",
+ "F: X; param1=\"=?charset?Q?value_1=E9?=\"",
+ p1.generate(vmime::generationContext::PARAMETER_VALUE_RFC2047_ONLY)
+ );
+
+ VASSERT_EQ(
+ "1.rfc2231",
+ "F: X; param1*=charset''value%201%E9",
+ p1.generate(vmime::generationContext::PARAMETER_VALUE_RFC2231_ONLY)
+ );
+
+ VASSERT_EQ(
+ "1.both",
+ "F: X; param1=\"=?charset?Q?value_1=E9?=\";param1*=charset''value%201%E9",
+ p1.generate(vmime::generationContext::PARAMETER_VALUE_RFC2231_AND_RFC2047)
+ );
+
+ // Value that spans on multiple lines
+ parameterizedHeaderField p2;
+ p2.appendParameter(
+ vmime::make_shared <vmime::parameter>(
+ "param1",
+ vmime::word(
+ "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ",
+ vmime::charset("charset")
+ )
+ )
+ );
+
+ VASSERT_EQ(
+ "2.no-encoding",
+ "F: X; \r\n "
+ "param1=abcdefghijkl",
+ p2.generate(vmime::generationContext::PARAMETER_VALUE_NO_ENCODING, 25) // max line length = 25
+ );
+
+ VASSERT_EQ(
+ "2.rfc2047",
+ "F: X; \r\n "
+ "param1=abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ",
+ p2.generate(vmime::generationContext::PARAMETER_VALUE_RFC2047_ONLY, 25) // max line length = 25
+ );
+
+ VASSERT_EQ(
+ "2.rfc2231",
+ "F: X; \r\n "
+ "param1*0*=charset''abc;\r\n "
+ "param1*1*=defghijkl;\r\n "
+ "param1*2*=mnopqrstu;\r\n "
+ "param1*3*=vwxyzABCD;\r\n "
+ "param1*4*=EFGHIJKLM;\r\n "
+ "param1*5*=NOPQRSTUV;\r\n "
+ "param1*6*=WXYZ",
+ p2.generate(vmime::generationContext::PARAMETER_VALUE_RFC2231_ONLY, 25) // max line length = 25
+ );
+
+ VASSERT_EQ(
+ "2.both",
+ "F: X; \r\n "
+ "param1=abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ;\r\n "
+ "param1*0*=charset''abc;\r\n "
+ "param1*1*=defghijkl;\r\n "
+ "param1*2*=mnopqrstu;\r\n "
+ "param1*3*=vwxyzABCD;\r\n "
+ "param1*4*=EFGHIJKLM;\r\n "
+ "param1*5*=NOPQRSTUV;\r\n "
+ "param1*6*=WXYZ",
+ p2.generate(vmime::generationContext::PARAMETER_VALUE_RFC2231_AND_RFC2047, 25) // max line length = 25
+ );
+
+ // Non-ASCII parameter value
+ parameterizedHeaderField p3;
+ p3.appendParameter(
+ vmime::make_shared <vmime::parameter>(
+ "param1",
+ vmime::word(
+ "δσσσσσσσσσσσσσσσσσσσσδσδα δσαδσδσαδσαδασδασ δσαδασδσα δσαδασδσα δασδασδασ δασαχφδδσα 2008.doc",
+ vmime::charset("utf-8")
+ )
+ )
+ );
+
+ VASSERT_EQ(
+ "3.no-encoding",
+ "F: X; \r\n "
+ "param1=\" 2008.doc\"",
+ p3.generate(vmime::generationContext::PARAMETER_VALUE_NO_ENCODING, 80) // max line length = 80
+ );
+
+ VASSERT_EQ(
+ "3.7bit-only",
+ "F: X; \r\n "
+ "param1=\"=?utf-8?B?zrTPg8+Dz4PPg8+Dz4PPg8+Dz4PPg8+Dz4PPg8+Dz4PPg8+Dz4PPg8+DzrTPg860?=\r\n "
+ "=?utf-8?B?zrEgzrTPg86xzrTPg860z4POsc60z4POsc60zrHPg860zrHPgyDOtM+DzrHOtM6x?=\r\n "
+ "=?utf-8?B?z4POtM+DzrEgzrTPg86xzrTOsc+DzrTPg86xIM60zrHPg860zrHPg860zrHPgyDOtA==?=\r\n "
+ "=?utf-8?B?zrHPg86xz4fPhs60zrTPg86xIDIwMDguZG9j?=\"",
+ p3.generate(vmime::generationContext::PARAMETER_VALUE_RFC2047_ONLY, 80) // max line length = 80
+ );
+
+ VASSERT_EQ(
+ "3.both",
+ "F: X; \r\n "
+ "param1=\"=?utf-8?B?zrTPg8+Dz4PPg8+Dz4PPg8+Dz4PPg8+Dz4PPg8+Dz4PPg8+Dz4PPg8+DzrTPg860?=\r\n "
+ "=?utf-8?B?zrEgzrTPg86xzrTPg860z4POsc60z4POsc60zrHPg860zrHPgyDOtM+DzrHOtM6x?=\r\n "
+ "=?utf-8?B?z4POtM+DzrEgzrTPg86xzrTOsc+DzrTPg86xIM60zrHPg860zrHPg860zrHPgyDOtA==?=\r\n "
+ "=?utf-8?B?zrHPg86xz4fPhs60zrTPg86xIDIwMDguZG9j?=\";\r\n "
+ "param1*0*=utf-8''%CE%B4%CF%83%CF%83%CF%83%CF%83%CF%83%CF%83%CF%83%CF%83%CF%83;\r\n "
+ "param1*1*=%CF%83%CF%83%CF%83%CF%83%CF%83%CF%83%CF%83%CF%83%CF%83%CF%83%CF%83;\r\n "
+ "param1*2*=%CE%B4%CF%83%CE%B4%CE%B1%20%CE%B4%CF%83%CE%B1%CE%B4%CF%83%CE%B4%CF;\r\n "
+ "param1*3*=%83%CE%B1%CE%B4%CF%83%CE%B1%CE%B4%CE%B1%CF%83%CE%B4%CE%B1%CF%83%20;\r\n "
+ "param1*4*=%CE%B4%CF%83%CE%B1%CE%B4%CE%B1%CF%83%CE%B4%CF%83%CE%B1%20%CE%B4%CF;\r\n "
+ "param1*5*=%83%CE%B1%CE%B4%CE%B1%CF%83%CE%B4%CF%83%CE%B1%20%CE%B4%CE%B1%CF%83;\r\n "
+ "param1*6*=%CE%B4%CE%B1%CF%83%CE%B4%CE%B1%CF%83%20%CE%B4%CE%B1%CF%83%CE%B1%CF;\r\n "
+ "param1*7*=%87%CF%86%CE%B4%CE%B4%CF%83%CE%B1%202008.doc",
+ p3.generate(vmime::generationContext::PARAMETER_VALUE_RFC2231_AND_RFC2047, 80) // max line length = 80
+ );
+
+ VASSERT_EQ(
+ "3.either",
+ "F: X; param1*0*=utf-8''%CE%B4%CF%83%CF%83%CF%83%CF%83%CF%83%CF%83%CF%83%CF%83%CF%83;\r\n "
+ "param1*1*=%CF%83%CF%83%CF%83%CF%83%CF%83%CF%83%CF%83%CF%83%CF%83%CF%83%CF%83;\r\n "
+ "param1*2*=%CE%B4%CF%83%CE%B4%CE%B1%20%CE%B4%CF%83%CE%B1%CE%B4%CF%83%CE%B4%CF;\r\n "
+ "param1*3*=%83%CE%B1%CE%B4%CF%83%CE%B1%CE%B4%CE%B1%CF%83%CE%B4%CE%B1%CF%83%20;\r\n "
+ "param1*4*=%CE%B4%CF%83%CE%B1%CE%B4%CE%B1%CF%83%CE%B4%CF%83%CE%B1%20%CE%B4%CF;\r\n "
+ "param1*5*=%83%CE%B1%CE%B4%CE%B1%CF%83%CE%B4%CF%83%CE%B1%20%CE%B4%CE%B1%CF%83;\r\n "
+ "param1*6*=%CE%B4%CE%B1%CF%83%CE%B4%CE%B1%CF%83%20%CE%B4%CE%B1%CF%83%CE%B1%CF;\r\n "
+ "param1*7*=%87%CF%86%CE%B4%CE%B4%CF%83%CE%B1%202008.doc",
+ p3.generate(vmime::generationContext::PARAMETER_VALUE_RFC2231_ONLY, 80) // max line length = 80
+ );
+
+ // No encoding needed
+ parameterizedHeaderField p4;
+ p4.appendParameter(
+ vmime::make_shared <vmime::parameter>(
+ "param1",
+ vmime::word("va lue", vmime::charset("charset"))
+ )
+ );
+
+ VASSERT_EQ(
+ "4.no-encoding",
+ "F: X; param1=\"va lue\"",
+ p4.generate(vmime::generationContext::PARAMETER_VALUE_NO_ENCODING)
+ );
+
+ VASSERT_EQ(
+ "4.rfc2047",
+ "F: X; param1=\"va lue\"",
+ p4.generate(vmime::generationContext::PARAMETER_VALUE_RFC2047_ONLY)
+ );
+
+ VASSERT_EQ(
+ "4.rfc2231",
+ "F: X; param1=\"va lue\"",
+ p4.generate(vmime::generationContext::PARAMETER_VALUE_RFC2231_ONLY)
+ );
+
+ VASSERT_EQ(
+ "4.both",
+ "F: X; param1=\"va lue\"",
+ p4.generate(vmime::generationContext::PARAMETER_VALUE_RFC2231_AND_RFC2047)
+ );
+
+ // Language specification
+ parameterizedHeaderField p5;
+ p5.appendParameter(
+ vmime::make_shared <vmime::parameter>("param1",
+ vmime::word("This is ***fun***", vmime::charset("us-ascii"), "en-us"))
+ );
+
+ VASSERT_EQ(
+ "5.no-encoding",
+ "F: X; param1=\"This is ***fun***\"",
+ p5.generate(vmime::generationContext::PARAMETER_VALUE_NO_ENCODING)
+ );
+
+ VASSERT_EQ(
+ "5.rfc2047",
+ "F: X; param1=\"=?us-ascii*en-us?Q?This_is_***fun***?=\"",
+ p5.generate(vmime::generationContext::PARAMETER_VALUE_RFC2047_ONLY)
+ );
+
+ VASSERT_EQ(
+ "5.rfc2231",
+ "F: X; param1*=us-ascii''This%20is%20***fun***",
+ p5.generate(vmime::generationContext::PARAMETER_VALUE_RFC2231_ONLY)
+ );
+
+ VASSERT_EQ(
+ "5.both",
+ "F: X; "
+ "param1=\"=?us-ascii*en-us?Q?This_is_***fun***?=\";\r\n "
+ "param1*=us-ascii''This%20is%20***fun***",
+ p5.generate(vmime::generationContext::PARAMETER_VALUE_RFC2231_AND_RFC2047));
+ }
+
+ void testGetGeneratedSizeRFC2231() {
+
+ vmime::generationContext ctx(vmime::generationContext::getDefaultContext());
+
+ // Extended parameter with charset specifier
+ vmime::parameter p1(
+ "param1",
+ vmime::word("value 1\xe9", vmime::charset("charset"))
+ );
+
+ ctx.setEncodedParameterValueMode(vmime::generationContext::PARAMETER_VALUE_NO_ENCODING);
+ VASSERT("1.no-encoding", p1.getGeneratedSize(ctx) >= generateParameter(p1, ctx).length());
+
+ ctx.setEncodedParameterValueMode(vmime::generationContext::PARAMETER_VALUE_RFC2047_ONLY);
+ VASSERT("1.rfc2047", p1.getGeneratedSize(ctx) >= generateParameter(p1, ctx).length());
+
+ ctx.setEncodedParameterValueMode(vmime::generationContext::PARAMETER_VALUE_RFC2231_ONLY);
+ VASSERT("1.rfc2231", p1.getGeneratedSize(ctx) >= generateParameter(p1, ctx).length());
+
+ ctx.setEncodedParameterValueMode(vmime::generationContext::PARAMETER_VALUE_RFC2231_AND_RFC2047);
+ VASSERT("1.both", p1.getGeneratedSize(ctx) >= generateParameter(p1, ctx).length());
+
+ // Value that spans on multiple lines
+ vmime::parameter p2(
+ "param1",
+ vmime::word(
+ "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ",
+ vmime::charset("charset")
+ )
+ );
+
+ ctx.setMaxLineLength(25);
+ ctx.setEncodedParameterValueMode(vmime::generationContext::PARAMETER_VALUE_NO_ENCODING);
+ VASSERT("2.no-encoding", p2.getGeneratedSize(ctx) >= generateParameter(p2, ctx).length());
+
+ ctx.setEncodedParameterValueMode(vmime::generationContext::PARAMETER_VALUE_RFC2047_ONLY);
+ VASSERT("2.rfc2047", p2.getGeneratedSize(ctx) >= generateParameter(p2, ctx).length());
+
+ ctx.setEncodedParameterValueMode(vmime::generationContext::PARAMETER_VALUE_RFC2231_ONLY);
+ VASSERT("2.rfc2231", p2.getGeneratedSize(ctx) >= generateParameter(p2, ctx).length());
+
+ ctx.setEncodedParameterValueMode(vmime::generationContext::PARAMETER_VALUE_RFC2231_AND_RFC2047);
+ VASSERT("2.both", p2.getGeneratedSize(ctx) >= generateParameter(p2, ctx).length());
+
+ // Non-ASCII parameter value
+ vmime::parameter p3(
+ "param1",
+ vmime::word(
+ "δσσσσσσσσσσσσσσσσσσσσδσδα δσαδσδσαδσαδασδασ δσαδασδσα δσαδασδσα δασδασδασ δασαχφδδσα 2008.doc",
+ vmime::charset("utf-8")
+ )
+ );
+
+ ctx.setMaxLineLength(vmime::generationContext::getDefaultContext().getMaxLineLength());
+ ctx.setEncodedParameterValueMode(vmime::generationContext::PARAMETER_VALUE_NO_ENCODING);
+ VASSERT("3.no-encoding", p3.getGeneratedSize(ctx) >= generateParameter(p3, ctx).length());
+
+ ctx.setEncodedParameterValueMode(vmime::generationContext::PARAMETER_VALUE_RFC2047_ONLY);
+ VASSERT("3.rfc2047", p3.getGeneratedSize(ctx) >= generateParameter(p3, ctx).length());
+
+ ctx.setEncodedParameterValueMode(vmime::generationContext::PARAMETER_VALUE_RFC2231_ONLY);
+ VASSERT("3.rfc2231", p3.getGeneratedSize(ctx) >= generateParameter(p3, ctx).length());
+
+ ctx.setEncodedParameterValueMode(vmime::generationContext::PARAMETER_VALUE_RFC2231_AND_RFC2047);
+ VASSERT("3.both", p3.getGeneratedSize(ctx) >= generateParameter(p3, ctx).length());
+
+ // No encoding needed
+ vmime::parameter p4(
+ "param1",
+ vmime::word("va lue", vmime::charset("charset"))
+ );
+
+ ctx.setMaxLineLength(vmime::generationContext::getDefaultContext().getMaxLineLength());
+ ctx.setEncodedParameterValueMode(vmime::generationContext::PARAMETER_VALUE_NO_ENCODING);
+ VASSERT("4.no-encoding", p4.getGeneratedSize(ctx) >= generateParameter(p4, ctx).length());
+
+ ctx.setEncodedParameterValueMode(vmime::generationContext::PARAMETER_VALUE_RFC2047_ONLY);
+ VASSERT("4.rfc2047", p4.getGeneratedSize(ctx) >= generateParameter(p4, ctx).length());
+
+ ctx.setEncodedParameterValueMode(vmime::generationContext::PARAMETER_VALUE_RFC2231_ONLY);
+ VASSERT("4.rfc2231", p4.getGeneratedSize(ctx) >= generateParameter(p4, ctx).length());
+
+ ctx.setEncodedParameterValueMode(vmime::generationContext::PARAMETER_VALUE_RFC2231_AND_RFC2047);
+ VASSERT("4.both", p4.getGeneratedSize(ctx) >= generateParameter(p4, ctx).length());
+
+ // Language specification
+ vmime::parameter p5(
+ "param1",
+ vmime::word("This is ***fun***", vmime::charset("us-ascii"), "en-us")
+ );
+
+ ctx.setMaxLineLength(vmime::generationContext::getDefaultContext().getMaxLineLength());
+ ctx.setEncodedParameterValueMode(vmime::generationContext::PARAMETER_VALUE_NO_ENCODING);
+ VASSERT("5.no-encoding", p5.getGeneratedSize(ctx) >= generateParameter(p5, ctx).length());
+
+ ctx.setEncodedParameterValueMode(vmime::generationContext::PARAMETER_VALUE_RFC2047_ONLY);
+ VASSERT("5.rfc2047", p5.getGeneratedSize(ctx) >= generateParameter(p5, ctx).length());
+
+ ctx.setEncodedParameterValueMode(vmime::generationContext::PARAMETER_VALUE_RFC2231_ONLY);
+ VASSERT("5.rfc2231", p5.getGeneratedSize(ctx) >= generateParameter(p5, ctx).length());
+
+ ctx.setEncodedParameterValueMode(vmime::generationContext::PARAMETER_VALUE_RFC2231_AND_RFC2047);
+ VASSERT("5.both", p5.getGeneratedSize(ctx) >= generateParameter(p5, ctx).length());
+ }
+
+ void testNonStandardEncodedParam() {
+
+ // This syntax is non-standard (expressly prohibited
+ // by RFC-2047), but is used by Mozilla:
+ //
+ // Content-Type: image/png;
+ // name="=?us-ascii?Q?Logo_VMime=2Epng?="
+
+ parameterizedHeaderField p1;
+ p1.parse("image/png; name=\"=?us-ascii?Q?Logo_VMime=2Epng?=\"");
+
+ VASSERT_EQ("1.1", 1, p1.getParameterCount());
+ VASSERT_EQ("1.2", "name", PARAM_NAME(p1, 0));
+ VASSERT_EQ("1.3", "Logo VMime.png", PARAM_VALUE(p1, 0));
+
+ parameterizedHeaderField p2;
+ p2.parse("image/png; name=\"Logo =?us-ascii?Q?VMime=2Epng?=\"");
+
+ VASSERT_EQ("2.1", 1, p2.getParameterCount());
+ VASSERT_EQ("2.2", "name", PARAM_NAME(p2, 0));
+ VASSERT_EQ("2.3", "Logo VMime.png", PARAM_VALUE(p2, 0));
+ }
+
+ // Parse parameters with non-significant whitespaces
+ void testParseNonSignificantWS() {
+
+ parameterizedHeaderField p1;
+ p1.parse(" \t X \r\n");
+
+ VASSERT_EQ("1.1", "X", FIELD_VALUE(p1));
+
+ parameterizedHeaderField p2;
+ p2.parse(" X ; param1 = value1 \r\n");
+
+ VASSERT_EQ("2.1", 1, p2.getParameterCount());
+ VASSERT_EQ("2.2", "X", FIELD_VALUE(p2));
+ VASSERT_EQ("2.3", "param1", PARAM_NAME(p2, 0));
+ VASSERT_EQ("2.4", "value1", PARAM_VALUE(p2, 0));
+ }
+
+ // Encode "tspecials"
+ void testEncodeTSpecials() {
+
+ VASSERT_EQ(" 1", "p=\"val(ue\"", vmime::make_shared <vmime::parameter>("p", "val(ue")->generate());
+ VASSERT_EQ(" 2", "p=\"val)ue\"", vmime::make_shared <vmime::parameter>("p", "val)ue")->generate());
+ VASSERT_EQ(" 3", "p=\"val<ue\"", vmime::make_shared <vmime::parameter>("p", "val<ue")->generate());
+ VASSERT_EQ(" 4", "p=\"val>ue\"", vmime::make_shared <vmime::parameter>("p", "val>ue")->generate());
+ VASSERT_EQ(" 5", "p=\"val@ue\"", vmime::make_shared <vmime::parameter>("p", "val@ue")->generate());
+ VASSERT_EQ(" 6", "p=\"val,ue\"", vmime::make_shared <vmime::parameter>("p", "val,ue")->generate());
+ VASSERT_EQ(" 7", "p=\"val;ue\"", vmime::make_shared <vmime::parameter>("p", "val;ue")->generate());
+ VASSERT_EQ(" 8", "p=\"val:ue\"", vmime::make_shared <vmime::parameter>("p", "val:ue")->generate());
+ VASSERT_EQ(" 9", "p=\"val/ue\"", vmime::make_shared <vmime::parameter>("p", "val/ue")->generate());
+ VASSERT_EQ("10", "p=\"val[ue\"", vmime::make_shared <vmime::parameter>("p", "val[ue")->generate());
+ VASSERT_EQ("11", "p=\"val]ue\"", vmime::make_shared <vmime::parameter>("p", "val]ue")->generate());
+ VASSERT_EQ("12", "p=\"val?ue\"", vmime::make_shared <vmime::parameter>("p", "val?ue")->generate());
+ VASSERT_EQ("13", "p=\"val=ue\"", vmime::make_shared <vmime::parameter>("p", "val=ue")->generate());
+ VASSERT_EQ("14", "p=\"val ue\"", vmime::make_shared <vmime::parameter>("p", "val ue")->generate());
+ VASSERT_EQ("15", "p=\"val\tue\"", vmime::make_shared <vmime::parameter>("p", "val\tue")->generate());
+ }
+
+ // http://sourceforge.net/projects/vmime/forums/forum/237356/topic/3812278
+ void testEncodeTSpecialsInRFC2231() {
+
+ VASSERT_EQ(
+ "1",
+ "filename*=UTF-8''my_file_name_%C3%B6%C3%A4%C3%BC_%281%29.txt",
+ vmime::make_shared <vmime::parameter>(
+ "filename",
+ vmime::word("my_file_name_\xc3\xb6\xc3\xa4\xc3\xbc_(1).txt", "UTF-8")
+ )->generate()
+ );
+ }
+
+ void testWhitespaceBreaksTheValue() {
+
+ parameterizedHeaderField p;
+ p.parse("xxx yyy; param1=value1 \r\n");
+
+ VASSERT_EQ("count", 1, p.getParameterCount());
+ VASSERT_EQ("value", "xxx", FIELD_VALUE(p));
+ VASSERT_EQ("param1.name", "param1", PARAM_NAME(p, 0));
+ VASSERT_EQ("param1.value", "value1", PARAM_VALUE(p, 0));
+ }
+
+VMIME_TEST_SUITE_END
diff --git a/vmime-master/tests/parser/pathTest.cpp b/vmime-master/tests/parser/pathTest.cpp
new file mode 100644
index 0000000..1396911
--- /dev/null
+++ b/vmime-master/tests/parser/pathTest.cpp
@@ -0,0 +1,102 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "tests/testUtils.hpp"
+
+
+VMIME_TEST_SUITE_BEGIN(pathTest)
+
+ VMIME_TEST_LIST_BEGIN
+ VMIME_TEST(testParse)
+ VMIME_TEST(testParse2)
+ VMIME_TEST(testGenerate)
+ VMIME_TEST_LIST_END
+
+
+ void testParse() {
+
+ vmime::path p1;
+ p1.parse("<>");
+
+ VASSERT_EQ("1.1", "", p1.getLocalPart());
+ VASSERT_EQ("1.2", "", p1.getDomain());
+
+ vmime::path p2;
+ p2.parse("<domain>");
+
+ VASSERT_EQ("2.1", "", p2.getLocalPart());
+ VASSERT_EQ("2.2", "domain", p2.getDomain());
+
+ vmime::path p3;
+ p3.parse("<local@domain>");
+
+ VASSERT_EQ("3.1", "local", p3.getLocalPart());
+ VASSERT_EQ("3.2", "domain", p3.getDomain());
+ }
+
+ void testParse2() {
+
+ // Test some invalid paths (no '<>')
+ vmime::path p1;
+ p1.parse("");
+
+ VASSERT_EQ("1.1", "", p1.getLocalPart());
+ VASSERT_EQ("1.2", "", p1.getDomain());
+
+ vmime::path p2;
+ p2.parse("domain");
+
+ VASSERT_EQ("2.1", "", p2.getLocalPart());
+ VASSERT_EQ("2.2", "domain", p2.getDomain());
+
+ vmime::path p3;
+ p3.parse("local@domain");
+
+ VASSERT_EQ("3.1", "local", p3.getLocalPart());
+ VASSERT_EQ("3.2", "domain", p3.getDomain());
+ }
+
+ void testGenerate() {
+
+ vmime::path p1;
+
+ VASSERT_EQ("1", "<>", p1.generate());
+
+ vmime::path p2;
+ p2.setLocalPart("local");
+
+ VASSERT_EQ("2", "<local@>", p2.generate());
+
+ vmime::path p3;
+ p3.setDomain("domain");
+
+ VASSERT_EQ("3", "<@domain>", p3.generate());
+
+ vmime::path p4;
+ p4.setLocalPart("local");
+ p4.setDomain("domain");
+
+ VASSERT_EQ("4", "<local@domain>", p4.generate());
+ }
+
+VMIME_TEST_SUITE_END
diff --git a/vmime-master/tests/parser/streamContentHandlerTest.cpp b/vmime-master/tests/parser/streamContentHandlerTest.cpp
new file mode 100644
index 0000000..399118e
--- /dev/null
+++ b/vmime-master/tests/parser/streamContentHandlerTest.cpp
@@ -0,0 +1,194 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "tests/testUtils.hpp"
+
+#include "vmime/utility/outputStreamAdapter.hpp"
+
+
+VMIME_TEST_SUITE_BEGIN(streamContentHandlerTest)
+
+ VMIME_TEST_LIST_BEGIN
+ VMIME_TEST(testIsEmpty)
+ VMIME_TEST(testGetLength)
+ VMIME_TEST(testIsEncoded)
+ VMIME_TEST(testGetLength_Encoded)
+ VMIME_TEST(testExtract)
+ VMIME_TEST(testExtract_Encoded)
+ VMIME_TEST(testExtractRaw_Encoded)
+ VMIME_TEST(testGenerate)
+ VMIME_TEST(testGenerate_Encoded)
+ VMIME_TEST_LIST_END
+
+
+ void testIsEmpty() {
+
+ vmime::streamContentHandler cth;
+
+ VASSERT_TRUE("empty", cth.isEmpty());
+ }
+
+ void testGetLength() {
+
+ vmime::string data("Test Data");
+ vmime::shared_ptr <vmime::utility::inputStream> stream =
+ vmime::make_shared <vmime::utility::inputStreamStringAdapter>(data);
+
+ vmime::streamContentHandler cth(stream, data.length());
+
+ VASSERT_FALSE("empty", cth.isEmpty());
+ VASSERT_EQ("length", 9, cth.getLength());
+ }
+
+ void testIsEncoded() {
+
+ vmime::string data("Test Data");
+ vmime::shared_ptr <vmime::utility::inputStream> stream =
+ vmime::make_shared <vmime::utility::inputStreamStringAdapter>(data);
+
+ vmime::streamContentHandler cth(stream, data.length());
+
+ VASSERT_FALSE("encoded", cth.isEncoded());
+ VASSERT_EQ("encoding", vmime::contentHandler::NO_ENCODING, cth.getEncoding());
+
+
+ vmime::string data2("Zm9vEjRWYmFy=");
+ vmime::shared_ptr <vmime::utility::inputStream> stream2 =
+ vmime::make_shared <vmime::utility::inputStreamStringAdapter>(data2);
+
+ vmime::streamContentHandler cth2(stream2, data2.length(), vmime::encoding("base64"));
+
+ VASSERT_TRUE("encoded", cth2.isEncoded());
+ VASSERT_EQ("encoding", "base64", cth2.getEncoding().generate());
+ }
+
+ void testGetLength_Encoded() {
+
+ vmime::string data("foo=12=34=56bar");
+ vmime::shared_ptr <vmime::utility::inputStream> stream =
+ vmime::make_shared <vmime::utility::inputStreamStringAdapter>(data);
+
+ vmime::streamContentHandler cth(stream, data.length(), vmime::encoding("quoted-printable"));
+
+ // Reported length should be the length of encoded data
+ VASSERT_EQ("length", 15, cth.getLength());
+ }
+
+ void testExtract() {
+
+ vmime::string data("Test Data");
+ vmime::shared_ptr <vmime::utility::inputStream> stream =
+ vmime::make_shared <vmime::utility::inputStreamStringAdapter>(data);
+
+ vmime::streamContentHandler cth(stream, data.length());
+
+ std::ostringstream oss;
+ vmime::utility::outputStreamAdapter osa(oss);
+
+ cth.extract(osa);
+
+ VASSERT_EQ("extract", "Test Data", oss.str());
+ }
+
+ void testExtract_Encoded() {
+
+ vmime::string data(
+ "QUJDREVGR0hJSktMTU5PUFFSU1RVVldYWVphYmNkZWZnaGlqa2xtbm9wcXJzdHV2d3h5ejAxMjM0NTY3ODk="
+ );
+
+ vmime::shared_ptr <vmime::utility::inputStream> stream =
+ vmime::make_shared <vmime::utility::inputStreamStringAdapter>(data);
+
+ vmime::streamContentHandler cth(stream, data.length(), vmime::encoding("base64"));
+
+ std::ostringstream oss;
+ vmime::utility::outputStreamAdapter osa(oss);
+
+ cth.extract(osa);
+
+ // Data should be decoded from B64
+ VASSERT_EQ(
+ "extract",
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789",
+ oss.str()
+ );
+ }
+
+ void testExtractRaw_Encoded()
+ {
+ vmime::string data(
+ "QUJDREVGR0hJSktMTU5PUFFSU1RVVldYWVphYmNkZWZnaGlqa2xtbm9wcXJzdHV2d3h5ejAxMjM0NTY3ODk="
+ );
+ vmime::shared_ptr <vmime::utility::inputStream> stream =
+ vmime::make_shared <vmime::utility::inputStreamStringAdapter>(data);
+
+ vmime::streamContentHandler cth(stream, data.length(), vmime::encoding("base64"));
+
+ std::ostringstream oss;
+ vmime::utility::outputStreamAdapter osa(oss);
+
+ cth.extractRaw(osa);
+
+ // Data should not be decoded
+ VASSERT_EQ(
+ "extractRaw",
+ "QUJDREVGR0hJSktMTU5PUFFSU1RVVldYWVphYmNkZWZnaGlqa2xtbm9wcXJzdHV2d3h5ejAxMjM0NTY3ODk=",
+ oss.str()
+ );
+ }
+
+ void testGenerate() {
+
+ vmime::string data("foo\x12\x34\x56 bar");
+ vmime::shared_ptr <vmime::utility::inputStream> stream =
+ vmime::make_shared <vmime::utility::inputStreamStringAdapter>(data);
+
+ vmime::streamContentHandler cth(stream, data.length());
+
+ std::ostringstream oss;
+ vmime::utility::outputStreamAdapter osa(oss);
+
+ cth.generate(osa, vmime::encoding("base64"));
+
+ // Data should be encoded to B64
+ VASSERT_EQ("generate", "Zm9vEjRWIGJhcg==", oss.str());
+ }
+
+ void testGenerate_Encoded() {
+
+ vmime::string data("foo=12=34=56bar");
+ vmime::shared_ptr <vmime::utility::inputStream> stream =
+ vmime::make_shared <vmime::utility::inputStreamStringAdapter>(data);
+
+ vmime::streamContentHandler cth(stream, data.length(), vmime::encoding("quoted-printable"));
+
+ std::ostringstream oss;
+ vmime::utility::outputStreamAdapter osa(oss);
+
+ cth.generate(osa, vmime::encoding("base64"));
+
+ // Data should be reencoded from QP to B64
+ VASSERT_EQ("generate", "Zm9vEjRWYmFy", oss.str());
+ }
+
+VMIME_TEST_SUITE_END
diff --git a/vmime-master/tests/parser/stringContentHandlerTest.cpp b/vmime-master/tests/parser/stringContentHandlerTest.cpp
new file mode 100644
index 0000000..c856301
--- /dev/null
+++ b/vmime-master/tests/parser/stringContentHandlerTest.cpp
@@ -0,0 +1,165 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "tests/testUtils.hpp"
+
+#include "vmime/utility/outputStreamAdapter.hpp"
+
+
+VMIME_TEST_SUITE_BEGIN(stringContentHandlerTest)
+
+ VMIME_TEST_LIST_BEGIN
+ VMIME_TEST(testIsEmpty)
+ VMIME_TEST(testGetLength)
+ VMIME_TEST(testIsEncoded)
+ VMIME_TEST(testGetLength_Encoded)
+ VMIME_TEST(testExtract)
+ VMIME_TEST(testExtract_Encoded)
+ VMIME_TEST(testExtractRaw_Encoded)
+ VMIME_TEST(testGenerate)
+ VMIME_TEST(testGenerate_Encoded)
+ VMIME_TEST_LIST_END
+
+
+ void testIsEmpty() {
+
+ vmime::stringContentHandler cth;
+
+ VASSERT_TRUE("empty", cth.isEmpty());
+ }
+
+ void testGetLength() {
+
+ vmime::stringContentHandler cth("Test Data");
+
+ VASSERT_FALSE("empty", cth.isEmpty());
+ VASSERT_EQ("length", 9, cth.getLength());
+ }
+
+ void testIsEncoded() {
+
+ vmime::stringContentHandler cth("Test Data");
+
+ VASSERT_FALSE("encoded", cth.isEncoded());
+ VASSERT_EQ("encoding", vmime::contentHandler::NO_ENCODING, cth.getEncoding());
+
+
+ vmime::stringContentHandler cth2("Zm9vEjRWYmFy=", vmime::encoding("base64"));
+
+ VASSERT_TRUE("encoded", cth2.isEncoded());
+ VASSERT_EQ("encoding", "base64", cth2.getEncoding().generate());
+ }
+
+ void testGetLength_Encoded() {
+
+ vmime::stringContentHandler cth(
+ "foo=12=34=56bar",
+ vmime::encoding("quoted-printable")
+ );
+
+ // Reported length should be the length of encoded data
+ VASSERT_EQ("length", 15, cth.getLength());
+ }
+
+ void testExtract() {
+
+ vmime::stringContentHandler cth("Test Data");
+
+ std::ostringstream oss;
+ vmime::utility::outputStreamAdapter osa(oss);
+
+ cth.extract(osa);
+
+ VASSERT_EQ("extract", "Test Data", oss.str());
+ }
+
+ void testExtract_Encoded() {
+
+ vmime::stringContentHandler cth(
+ "QUJDREVGR0hJSktMTU5PUFFSU1RVVldYWVphYmNkZWZnaGlqa2xtbm9wcXJzdHV2d3h5ejAxMjM0NTY3ODk=",
+ vmime::encoding("base64")
+ );
+
+ std::ostringstream oss;
+ vmime::utility::outputStreamAdapter osa(oss);
+
+ cth.extract(osa);
+
+ // Data should be decoded from B64
+ VASSERT_EQ(
+ "extract",
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789",
+ oss.str()
+ );
+ }
+
+ void testExtractRaw_Encoded() {
+
+ vmime::stringContentHandler cth(
+ "QUJDREVGR0hJSktMTU5PUFFSU1RVVldYWVphYmNkZWZnaGlqa2xtbm9wcXJzdHV2d3h5ejAxMjM0NTY3ODk=",
+ vmime::encoding("base64")
+ );
+
+ std::ostringstream oss;
+ vmime::utility::outputStreamAdapter osa(oss);
+
+ cth.extractRaw(osa);
+
+ // Data should not be decoded
+ VASSERT_EQ(
+ "extractRaw",
+ "QUJDREVGR0hJSktMTU5PUFFSU1RVVldYWVphYmNkZWZnaGlqa2xtbm9wcXJzdHV2d3h5ejAxMjM0NTY3ODk=",
+ oss.str()
+ );
+ }
+
+ void testGenerate() {
+
+ vmime::stringContentHandler cth("foo\x12\x34\x56 bar");
+
+ std::ostringstream oss;
+ vmime::utility::outputStreamAdapter osa(oss);
+
+ cth.generate(osa, vmime::encoding("base64"));
+
+ // Data should be encoded to B64
+ VASSERT_EQ("generate", "Zm9vEjRWIGJhcg==", oss.str());
+ }
+
+ void testGenerate_Encoded() {
+
+ vmime::stringContentHandler cth(
+ "foo=12=34=56bar",
+ vmime::encoding("quoted-printable")
+ );
+
+ std::ostringstream oss;
+ vmime::utility::outputStreamAdapter osa(oss);
+
+ cth.generate(osa, vmime::encoding("base64"));
+
+ // Data should be reencoded from QP to B64
+ VASSERT_EQ("generate", "Zm9vEjRWYmFy", oss.str());
+ }
+
+VMIME_TEST_SUITE_END
diff --git a/vmime-master/tests/parser/textTest.cpp b/vmime-master/tests/parser/textTest.cpp
new file mode 100644
index 0000000..e9ddc26
--- /dev/null
+++ b/vmime-master/tests/parser/textTest.cpp
@@ -0,0 +1,918 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "tests/testUtils.hpp"
+
+#include <locale>
+#include <clocale>
+
+
+VMIME_TEST_SUITE_BEGIN(textTest)
+
+ VMIME_TEST_LIST_BEGIN
+ VMIME_TEST(testConstructors)
+ VMIME_TEST(testCopy)
+ VMIME_TEST(testNewFromString)
+ VMIME_TEST(testDisplayForm)
+ VMIME_TEST(testParse)
+ VMIME_TEST(testGenerate)
+
+ VMIME_TEST(testWordConstructors)
+ VMIME_TEST(testWordParse)
+ VMIME_TEST(testWordGenerate)
+ VMIME_TEST(testWordGenerateSpace)
+ VMIME_TEST(testWordGenerateSpace2)
+ VMIME_TEST(testWordGenerateMultiBytes)
+ VMIME_TEST(testWordGenerateQuote)
+ VMIME_TEST(testWordGenerateSpecialCharsets)
+ VMIME_TEST(testWordGenerateSpecials)
+
+ VMIME_TEST(testWhitespace)
+ VMIME_TEST(testWhitespaceMBox)
+
+ VMIME_TEST(testFoldingAscii)
+ VMIME_TEST(testForcedNonEncoding)
+
+ VMIME_TEST(testBugFix20110511)
+
+ VMIME_TEST(testInternationalizedEmail_specialChars)
+ VMIME_TEST(testInternationalizedEmail_UTF8)
+ VMIME_TEST(testInternationalizedEmail_nonUTF8)
+ VMIME_TEST(testInternationalizedEmail_folding)
+ VMIME_TEST(testInternationalizedEmail_whitespace)
+
+ VMIME_TEST(testWronglyPaddedB64Words)
+ VMIME_TEST(testFixBrokenWords)
+ VMIME_TEST(testUnknownCharset)
+ VMIME_TEST_LIST_END
+
+
+ static const vmime::string getDisplayText(const vmime::text& t) {
+
+ return t.getWholeBuffer();
+ }
+
+ static const vmime::string cleanGeneratedWords(const std::string& str) {
+
+ std::istringstream iss(str);
+
+ std::string res;
+ std::string x;
+
+ while (std::getline(iss, x)) {
+ res += vmime::utility::stringUtils::trim(x);
+ }
+
+ return res;
+ }
+
+
+ void setUp() {
+
+ // Set the global C and C++ locale to the user-configured locale.
+ // The locale should use UTF-8 encoding for these tests to run successfully.
+ try {
+ std::locale::global(std::locale(""));
+ } catch (std::exception &) {
+ std::setlocale(LC_ALL, "");
+ }
+ }
+
+ void tearDown() {
+
+ // Restore default locale
+ std::locale::global(std::locale("C"));
+ }
+
+
+ void testConstructors() {
+
+ vmime::text t1;
+
+ VASSERT_EQ("1.1", 0, t1.getWordCount());
+
+ vmime::text t2("Test\xa9\xc3");
+
+ VASSERT_EQ("2.1", 1, t2.getWordCount());
+ VASSERT_EQ("2.2", "Test\xa9\xc3", t2.getWordAt(0)->getBuffer());
+ VASSERT_EQ("2.3", vmime::charset::getLocalCharset(), t2.getWordAt(0)->getCharset());
+
+ vmime::text t3("Test\xa9\xc3", vmime::charset(vmime::charsets::ISO8859_13));
+
+ VASSERT_EQ("3.1", 1, t3.getWordCount());
+ VASSERT_EQ("3.2", "Test\xa9\xc3", t3.getWordAt(0)->getBuffer());
+ VASSERT_EQ("3.3", vmime::charset(vmime::charsets::ISO8859_13), t3.getWordAt(0)->getCharset());
+
+ vmime::word w1("Test", vmime::charset(vmime::charsets::UTF_8));
+ vmime::text t4(w1);
+
+ VASSERT_EQ("4.1", 1, t4.getWordCount());
+ VASSERT_EQ("4.2", w1.getBuffer(), t4.getWordAt(0)->getBuffer());
+ VASSERT_EQ("4.3", w1.getCharset(), t4.getWordAt(0)->getCharset());
+
+ vmime::word w2("Other", vmime::charset(vmime::charsets::US_ASCII));
+ t4.appendWord(vmime::make_shared <vmime::word>(w2));
+
+ vmime::text t5(t4);
+
+ VASSERT_EQ("5.1", 2, t5.getWordCount());
+ VASSERT_EQ("5.2", w1.getBuffer(), t5.getWordAt(0)->getBuffer());
+ VASSERT_EQ("5.3", w1.getCharset(), t5.getWordAt(0)->getCharset());
+ VASSERT_EQ("5.4", w2.getBuffer(), t5.getWordAt(1)->getBuffer());
+ VASSERT_EQ("5.5", w2.getCharset(), t5.getWordAt(1)->getCharset());
+ }
+
+ void testCopy() {
+
+ vmime::text t1("Test: \xa9\xc3");
+
+ VASSERT("operator==", t1 == t1);
+ VASSERT("clone", *vmime::clone(t1) == t1);
+
+ vmime::text t2;
+ t2.copyFrom(t1);
+
+ VASSERT("copyFrom", t1 == t2);
+ }
+
+ void testNewFromString() {
+
+ vmime::string s1 = "only ASCII characters";
+ vmime::charset c1("test");
+ vmime::text t1;
+
+ t1.createFromString(s1, c1);
+
+ VASSERT_EQ("1.1", 1, t1.getWordCount());
+ VASSERT_EQ("1.2", s1, t1.getWordAt(0)->getBuffer());
+ VASSERT_EQ("1.3", vmime::charset(vmime::charsets::US_ASCII), t1.getWordAt(0)->getCharset());
+
+ vmime::string s2_1 = "some ASCII characters and special chars: ";
+ vmime::string s2_2 = "\xf1\xf2\xf3\xf4 ";
+ vmime::string s2_3 = "and then more ASCII chars.";
+ vmime::string s2 = s2_1 + s2_2 + s2_3;
+ vmime::charset c2("test");
+ vmime::text t2;
+
+ t2.createFromString(s2, c2);
+
+ VASSERT_EQ("2.1", 3, t2.getWordCount());
+ VASSERT_EQ("2.2", "some ASCII characters and special chars: ", t2.getWordAt(0)->getBuffer());
+ VASSERT_EQ("2.3", vmime::charset(vmime::charsets::US_ASCII), t2.getWordAt(0)->getCharset());
+ VASSERT_EQ("2.4", "\xf1\xf2\xf3\xf4", t2.getWordAt(1)->getBuffer());
+ VASSERT_EQ("2.5", c2, t2.getWordAt(1)->getCharset());
+ VASSERT_EQ("2.6", "and then more ASCII chars.", t2.getWordAt(2)->getBuffer());
+ VASSERT_EQ("2.7", vmime::charset(vmime::charsets::US_ASCII), t2.getWordAt(2)->getCharset());
+ }
+
+ static const vmime::string parseText(const vmime::string& buffer) {
+
+ vmime::text t;
+ t.parse(buffer);
+
+ std::ostringstream oss;
+ oss << t;
+
+ return oss.str();
+ }
+
+ void testParse() {
+
+ // From RFC-2047
+ VASSERT_EQ(
+ "1",
+ "[text: [[word: charset=US-ASCII, buffer=Keith Moore]]]",
+ parseText("=?US-ASCII?Q?Keith_Moore?=")
+ );
+
+ VASSERT_EQ(
+ "2",
+ "[text: [[word: charset=ISO-8859-1, buffer=Keld J\xf8rn Simonsen]]]",
+ parseText("=?ISO-8859-1?Q?Keld_J=F8rn_Simonsen?=")
+ );
+
+ VASSERT_EQ(
+ "3",
+ "[text: [[word: charset=ISO-8859-1, buffer=Andr\xe9]," \
+ "[word: charset=us-ascii, buffer= Pirard]]]",
+ parseText("=?ISO-8859-1?Q?Andr=E9?= Pirard")
+ );
+
+ VASSERT_EQ(
+ "4",
+ "[text: [[word: charset=ISO-8859-1, buffer=If you can read this yo]," \
+ "[word: charset=ISO-8859-2, buffer=u understand the example.]]]",
+ parseText(
+ "=?ISO-8859-1?B?SWYgeW91IGNhbiByZWFkIHRoaXMgeW8=?=\r\n " \
+ "=?ISO-8859-2?B?dSB1bmRlcnN0YW5kIHRoZSBleGFtcGxlLg==?="
+ )
+ );
+
+ // Bugfix: in "=?charset?q?=XX=YY?=", the "?=" finish
+ // sequence was not correctly found (should be the one
+ // after '=YY' and not the one after '?q').
+ VASSERT_EQ(
+ "5",
+ "[text: [[word: charset=abc, buffer=\xe9\xe9]]]",
+ parseText("=?abc?q?=E9=E9?=")
+ );
+
+ // Question marks (?) in the middle of the string
+ VASSERT_EQ(
+ "6",
+ "[text: [[word: charset=iso-8859-1, buffer=Know wh\xe4t? It works!]]]",
+ parseText("=?iso-8859-1?Q?Know_wh=E4t?_It_works!?=")
+ );
+
+ // With language specifier
+ VASSERT_EQ(
+ "7",
+ "[text: [[word: charset=US-ASCII, buffer=Keith Moore, lang=EN]]]",
+ parseText("=?US-ASCII*EN?Q?Keith_Moore?=")
+ );
+ }
+
+ void testGenerate() {
+
+ // TODO
+
+ // With language specifier
+ vmime::word wlang1("Émeline", vmime::charset("UTF-8"), "FR");
+ VASSERT_EQ("lang1", "=?UTF-8*FR?Q?=C3=89meline?=", wlang1.generate());
+
+ vmime::word wlang2("Keith Moore", vmime::charset("US-ASCII"), "EN");
+ VASSERT_EQ("lang2", "=?US-ASCII*EN?Q?Keith_Moore?=", wlang2.generate());
+ }
+
+ void testDisplayForm() {
+
+#define DISPLAY_FORM(x) getDisplayText(*vmime::text::decodeAndUnfold(x))
+
+ // From RFC-2047
+ VASSERT_EQ("1", "a", DISPLAY_FORM("=?ISO-8859-1?Q?a?="));
+ VASSERT_EQ("2", "a b", DISPLAY_FORM("=?ISO-8859-1?Q?a?= b"));
+ VASSERT_EQ("3", "ab", DISPLAY_FORM("=?ISO-8859-1?Q?a?= =?ISO-8859-1?Q?b?="));
+ VASSERT_EQ("4", "ab", DISPLAY_FORM("=?ISO-8859-1?Q?a?= \t =?ISO-8859-1?Q?b?="));
+ VASSERT_EQ("5", "ab", DISPLAY_FORM("=?ISO-8859-1?Q?a?= \r\n \t =?ISO-8859-1?Q?b?="));
+ VASSERT_EQ("6", "a b", DISPLAY_FORM("=?ISO-8859-1?Q?a_b?="));
+ VASSERT_EQ("7", "a b", DISPLAY_FORM("=?ISO-8859-1?Q?a?= =?ISO-8859-2?Q?_b?="));
+
+ // Some more tests...
+ VASSERT_EQ("8", "a b", DISPLAY_FORM(" a =?ISO-8859-1?Q?b?= "));
+ VASSERT_EQ("9", "a b ", DISPLAY_FORM(" \t =?ISO-8859-1?Q?a?= b "));
+ VASSERT_EQ("10", "a b", DISPLAY_FORM(" a\r\n\t b"));
+
+ VASSERT_EQ("11", "a b c", DISPLAY_FORM("a =?ISO-8859-1?Q?b?= c"));
+ VASSERT_EQ("12", "a b c ", DISPLAY_FORM("a =?ISO-8859-1?Q?b?= c "));
+ VASSERT_EQ("13", "a b c ", DISPLAY_FORM(" a =?ISO-8859-1?Q?b?= c "));
+ VASSERT_EQ("14", "a b c d", DISPLAY_FORM("a =?ISO-8859-1?Q?b?= c =?ISO-8859-1?Q?d?= "));
+ VASSERT_EQ("15", "a b c d e", DISPLAY_FORM("a =?ISO-8859-1?Q?b?= c =?ISO-8859-1?Q?d?= e"));
+
+ // Whitespaces and multiline
+ VASSERT_EQ("16", "a b c d e", DISPLAY_FORM("=?ISO-8859-1?Q?a_b_?=c\n\t=?ISO-8859-1?Q?d_?=e"));
+
+ // Ignored newlines
+ VASSERT_EQ("17", "ab", DISPLAY_FORM("=?ISO-8859-1?Q?a?=\r\nb"));
+ VASSERT_EQ("18", "a b", DISPLAY_FORM("=?ISO-8859-1?Q?a?= \r\nb"));
+
+#undef DISPLAY_FORM
+ }
+
+ void testWordConstructors() {
+
+ VASSERT_EQ("1.1", vmime::charset::getLocalCharset(), vmime::word().getCharset());
+ VASSERT_EQ("1.2", "", vmime::word().getBuffer());
+
+ VASSERT_EQ("2.1", vmime::charset::getLocalCharset(), vmime::word("foo").getCharset());
+ VASSERT_EQ("2.2", "foo", vmime::word("foo").getBuffer());
+
+ VASSERT_EQ("3.1", "bar", vmime::word("foo", vmime::charset("bar")).getCharset().getName());
+ VASSERT_EQ("3.2", "foo", vmime::word("foo", vmime::charset("bar")).getBuffer());
+ }
+
+ void testWordParse() {
+
+ // Simple encoded word
+ vmime::word w1;
+ w1.parse("=?foo?q?bar=E9 baz?=");
+
+ VASSERT_EQ("1.1", "foo", w1.getCharset().getName());
+ VASSERT_EQ("1.2", "bar\xe9 baz", w1.getBuffer());
+
+ // Unencoded text
+ vmime::word w2;
+ w2.parse(" foo bar \tbaz...");
+
+ VASSERT_EQ("2.1", vmime::charset(vmime::charsets::US_ASCII), w2.getCharset());
+ VASSERT_EQ("2.2", " foo bar \tbaz...", w2.getBuffer());
+
+ // Malformed word
+ vmime::word w3;
+ w3.parse("=?foo bar");
+
+ VASSERT_EQ("3.1", vmime::charset(vmime::charsets::US_ASCII), w3.getCharset());
+ VASSERT_EQ("3.2", "=?foo bar", w3.getBuffer());
+
+ // Unknown encoding
+ vmime::word w4;
+ w4.parse("=?whatever?not_q_or_b?whatever?=");
+
+ VASSERT_EQ("4.1", vmime::charset(vmime::charsets::US_ASCII), w4.getCharset());
+ VASSERT_EQ("4.2", "=?whatever?not_q_or_b?whatever?=", w4.getBuffer());
+ }
+
+ void testWordGenerate() {
+
+ VASSERT_EQ(
+ "1",
+ "=?foo?Q?bar=E9_baz?=",
+ vmime::word("bar\xe9 baz", vmime::charset("foo")).generate()
+ );
+
+ VASSERT_EQ(
+ "2",
+ "=?foo?B?8fLz9PU=?=",
+ vmime::word("\xf1\xf2\xf3\xf4\xf5", vmime::charset("foo")).generate()
+ );
+ }
+
+ void testWordGenerateSpace() {
+
+ // No white-space between an unencoded word and a encoded one
+ VASSERT_EQ(
+ "1",
+ "Bonjour =?utf-8?Q?Fran=C3=A7ois?=",
+ vmime::text::newFromString(
+ "Bonjour Fran\xc3\xa7ois",
+ vmime::charset("utf-8")
+ )->generate()
+ );
+
+ // White-space between two encoded words
+ vmime::text txt;
+ txt.appendWord(vmime::make_shared <vmime::word>("\xc3\x89t\xc3\xa9", "utf-8"));
+ txt.appendWord(vmime::make_shared <vmime::word>("Fran\xc3\xa7ois", "utf-8"));
+
+ const vmime::string decoded = "\xc3\x89t\xc3\xa9""Fran\xc3\xa7ois";
+ const vmime::string encoded = "=?utf-8?B?w4l0w6k=?= =?utf-8?Q?Fran=C3=A7ois?=";
+
+ // -- test encoding
+ VASSERT_EQ("2", encoded, txt.generate());
+
+ // -- ensure no space is added when decoding
+ vmime::text txt2;
+ txt2.parse(encoded, 0, encoded.length());
+
+ VASSERT_EQ("3", decoded, txt2.getWholeBuffer());
+
+ // -- test rencoding
+ VASSERT_EQ("4", encoded, txt2.generate());
+ }
+
+ void testWordGenerateSpace2() {
+
+ // White-space between two encoded words (#2)
+ vmime::text txt;
+ txt.appendWord(vmime::make_shared <vmime::word>("Facture ", "utf-8"));
+ txt.appendWord(vmime::make_shared <vmime::word>("\xc3\xa0", "utf-8"));
+ txt.appendWord(vmime::make_shared <vmime::word>(" envoyer ", "utf-8"));
+ txt.appendWord(vmime::make_shared <vmime::word>("\xc3\xa0", "utf-8"));
+ txt.appendWord(vmime::make_shared <vmime::word>(" Martine", "utf-8"));
+
+ const vmime::string decoded = "Facture ""\xc3\xa0"" envoyer ""\xc3\xa0"" Martine";
+ const vmime::string encoded = "Facture =?utf-8?B?w6A=?= envoyer =?utf-8?B?w6A=?= Martine";
+
+ // -- test encoding
+ VASSERT_EQ("1", encoded, txt.generate());
+
+ // -- ensure no space is added when decoding
+ vmime::text txt2;
+ txt2.parse(encoded, 0, encoded.length());
+
+ VASSERT_EQ("2", decoded, txt2.getWholeBuffer());
+
+ // -- test rencoding
+ VASSERT_EQ("3", encoded, txt2.generate());
+ }
+
+ void testWordGenerateMultiBytes() {
+
+ // Ensure we don't encode a non-integral number of characters
+ VASSERT_EQ(
+ "1",
+ "=?utf-8?Q?aaa?==?utf-8?Q?=C3=A9?==?utf-8?Q?zzz?=",
+ cleanGeneratedWords(
+ vmime::word("aaa\xc3\xa9zzz", vmime::charset("utf-8")).generate(16)
+ )
+ );
+
+ VASSERT_EQ(
+ "2",
+ "=?utf-8?Q?aaa=C3=A9?==?utf-8?Q?zzz?=",
+ cleanGeneratedWords(
+ vmime::word("aaa\xc3\xa9zzz", vmime::charset("utf-8")).generate(17)
+ )
+ );
+ }
+
+ void testWordGenerateQuote() {
+
+ std::string str;
+ vmime::utility::outputStreamStringAdapter os(str);
+
+ vmime::generationContext ctx;
+ ctx.setMaxLineLength(1000);
+
+ // ASCII-only text is quotable
+ str.clear();
+ vmime::word("Quoted text")
+ .generate(ctx, os, 0, NULL, vmime::text::QUOTE_IF_POSSIBLE, NULL);
+
+ VASSERT_EQ("1", "\"Quoted text\"", cleanGeneratedWords(str));
+
+ // Text with CR/LF is not quotable
+ str.clear();
+ vmime::word("Non-quotable\ntext", "us-ascii")
+ .generate(ctx, os, 0, NULL, vmime::text::QUOTE_IF_POSSIBLE, NULL);
+
+ VASSERT_EQ("2", "=?us-ascii?Q?Non-quotable=0Atext?=", cleanGeneratedWords(str));
+
+ // Text with non-ASCII chars is not quotable
+ str.clear();
+ vmime::word("Non-quotable text \xc3\xa9")
+ .generate(ctx, os, 0, NULL, vmime::text::QUOTE_IF_POSSIBLE, NULL);
+
+ VASSERT_EQ("3", "=?UTF-8?Q?Non-quotable_text_=C3=A9?=", cleanGeneratedWords(str));
+ }
+
+ void testWordGenerateSpecialCharsets() {
+
+ // ISO-2022-JP only uses 7-bit chars but should be encoded in Base64
+ VASSERT_EQ(
+ "1",
+ "=?iso-2022-jp?B?XlskQiVRITwlPSVKJWshJiU9JVUlSCUmJSclIl5bKEI=?=",
+ cleanGeneratedWords(
+ vmime::word(
+ "^[$B%Q!<%=%J%k!&%=%U%H%&%'%\"^[(B",
+ vmime::charset("iso-2022-jp")
+ ).generate(100)
+ )
+ );
+ }
+
+ void testWordGenerateSpecials() {
+
+ // In RFC-2047, quotation marks (ASCII 22h) should be encoded
+ VASSERT_EQ(
+ "1",
+ "=?UTF-8?Q?=22=C3=9Cml=C3=A4ute=22?=",
+ vmime::word(
+ "\x22\xC3\x9Cml\xC3\xA4ute\x22",
+ vmime::charset("UTF-8")
+ ).generate()
+ );
+ }
+
+ void testWhitespace() {
+
+ // Create
+ vmime::text text;
+ text.createFromString("Achim Br\xc3\xa4ndt", vmime::charsets::UTF_8);
+
+ VASSERT_EQ("1", 2, text.getWordCount());
+ VASSERT_EQ("2", "Achim ", text.getWordAt(0)->getBuffer());
+ VASSERT_EQ("3", "us-ascii", text.getWordAt(0)->getCharset());
+ VASSERT_EQ("4", "Br\xc3\xa4ndt", text.getWordAt(1)->getBuffer());
+ VASSERT_EQ("5", "utf-8", text.getWordAt(1)->getCharset());
+
+ // Generate
+ VASSERT_EQ("6", "Achim =?utf-8?Q?Br=C3=A4ndt?=", text.generate());
+
+ // Parse
+ text.parse("=?us-ascii?Q?Achim_?= =?utf-8?Q?Br=C3=A4ndt?=");
+
+ VASSERT_EQ("7", 2, text.getWordCount());
+ VASSERT_EQ("8", "Achim ", text.getWordAt(0)->getBuffer());
+ VASSERT_EQ("9", "us-ascii", text.getWordAt(0)->getCharset());
+ VASSERT_EQ("10", "Br\xc3\xa4ndt", text.getWordAt(1)->getBuffer());
+ VASSERT_EQ("11", "utf-8", text.getWordAt(1)->getCharset());
+ }
+
+ void testWhitespaceMBox() {
+
+ // Space MUST be encoded inside a word
+ vmime::mailbox mbox(vmime::text("Achim Br\xc3\xa4ndt", vmime::charsets::UTF_8), "me@vmime.org");
+ VASSERT_EQ("generate1", "=?us-ascii?Q?Achim_?= =?utf-8?Q?Br=C3=A4ndt?= <me@vmime.org>", mbox.generate());
+
+ vmime::text txt;
+ txt.appendWord(vmime::make_shared <vmime::word>("Achim ", "us-ascii"));
+ txt.appendWord(vmime::make_shared <vmime::word>("Br\xc3\xa4ndt", "utf-8"));
+ mbox = vmime::mailbox(txt, "me@vmime.org");
+ VASSERT_EQ("generate2", "=?us-ascii?Q?Achim_?= =?utf-8?Q?Br=C3=A4ndt?= <me@vmime.org>", mbox.generate());
+
+ mbox.parse("=?us-ascii?Q?Achim?= =?utf-8?Q?Br=C3=A4ndt?= <me@vmime.org>");
+ VASSERT_EQ("parse.name.count", 2, mbox.getName().getWordCount());
+ VASSERT_EQ("parse.name.word1.buffer", "Achim", mbox.getName().getWordAt(0)->getBuffer());
+ VASSERT_EQ("parse.name.word1.charset", "us-ascii", mbox.getName().getWordAt(0)->getCharset());
+ VASSERT_EQ("parse.name.word2.buffer", "Br\xc3\xa4ndt", mbox.getName().getWordAt(1)->getBuffer());
+ VASSERT_EQ("parse.name.word2.charset", "utf-8", mbox.getName().getWordAt(1)->getCharset());
+
+ VASSERT_EQ("parse.email", "me@vmime.org", mbox.getEmail());
+ }
+
+ void testFoldingAscii() {
+
+ // In this test, no encoding is needed, but line should be folded anyway
+ vmime::word w("01234567890123456789012345678901234567890123456789"
+ "01234567890123456789012345678901234567890123456789", vmime::charset("us-ascii"));
+
+ VASSERT_EQ(
+ "fold.ascii",
+ "=?us-ascii?Q?01234567890123456789012345678901234?=\r\n"
+ " =?us-ascii?Q?5678901234567890123456789012345678?=\r\n"
+ " =?us-ascii?Q?9012345678901234567890123456789?=", w.generate(50)
+ );
+ }
+
+ void testForcedNonEncoding() {
+
+ // Testing long unbreakable and unencodable header
+ vmime::relay r;
+ r.parse(
+ " from User (Ee9GMqZQ8t7IQwftfAFHd2KyScCYRrFSJ50tKEoXv2bVCG4HcPU80GGWiFabAvG77FekpGgF1h@[127.0.0.1]) by servername.hostname.com\n\t"
+ "with esmtp id 1NGTS9-2C0sqG0; Fri, 4 Dec 2009 09:23:49 +0100"
+ );
+
+ VASSERT_EQ(
+ "received.long",
+ "from User\r\n (Ee9GMqZQ8t7IQwftfAFHd2KyScCYRrFSJ50tKEoXv2bVCG4HcPU80GGWiFabAvG77FekpGgF1h@[127.0.0.1])\r\n by servername.hostname.com with esmtp id 1NGTS9-2C0sqG0; Fri, 4 Dec 2009\r\n 09:23:49 +0100",
+ r.generate(78)
+ );
+ }
+
+ void testBugFix20110511() {
+
+ /*
+
+ Using the latest version of vmime (0.9.1), encoding the following string: Jean
+ Gwenaël Dutourd will result in:
+ Jean =?utf-8?Q?Gwena=C3=ABl_?= Dutourd
+ However, decoding this will result in Jean Gwenaël Dutourd (notice two spaces
+ between the last 2 words). The encoder adds a _ after the second word, but
+ since the last word is not encoded, the space between them is not ignored, and
+ is decoded into an additional space.
+
+ See: http://sourceforge.net/projects/vmime/forums/forum/237357/topic/4531365
+
+ */
+
+ const std::string DECODED_TEXT = "Jean Gwenaël Dutourd";
+ const std::string ENCODED_TEXT = "Jean =?utf-8?Q?Gwena=C3=ABl?= Dutourd";
+
+ // Encode
+ VASSERT_EQ(
+ "encode",
+ ENCODED_TEXT,
+ vmime::text::newFromString(DECODED_TEXT, vmime::charset("utf-8"))->generate()
+ );
+
+ // Decode
+ vmime::text t;
+ t.parse(ENCODED_TEXT);
+
+ // -- words
+ std::ostringstream oss; oss << t;
+ VASSERT_EQ(
+ "decode1",
+ "[text: [[word: charset=us-ascii, buffer=Jean ],"
+ "[word: charset=utf-8, buffer=Gwenaël],"
+ "[word: charset=us-ascii, buffer= Dutourd]]]",
+ oss.str()
+ );
+
+ // -- getWholeBuffer
+ VASSERT_EQ("decode2", DECODED_TEXT, t.getWholeBuffer());
+ }
+
+ void testInternationalizedEmail_specialChars() {
+
+ vmime::generationContext ctx(vmime::generationContext::getDefaultContext());
+ ctx.setInternationalizedEmailSupport(true);
+
+ vmime::generationContext::switcher <vmime::generationContext> contextSwitcher(ctx);
+
+ // Special sequence/chars should still be encoded
+ VASSERT_EQ(
+ "1",
+ "=?us-ascii?Q?Test=3D=3Frfc2047_sequence?=",
+ vmime::word("Test=?rfc2047 sequence", vmime::charset("us-ascii")).generate()
+ );
+
+ VASSERT_EQ(
+ "2",
+ "=?us-ascii?Q?Line_One=0ALine_Two?=",
+ vmime::word("Line One\nLine Two", vmime::charset("us-ascii")).generate()
+ );
+ }
+
+ void testInternationalizedEmail_UTF8() {
+
+ vmime::generationContext ctx(vmime::generationContext::getDefaultContext());
+ ctx.setInternationalizedEmailSupport(true);
+
+ vmime::generationContext::switcher <vmime::generationContext> contextSwitcher(ctx);
+
+ // Already UTF-8 encoded text should be left as is
+ VASSERT_EQ(
+ "1", "Achim Br\xc3\xa4ndt",
+ vmime::word("Achim Br\xc3\xa4ndt", vmime::charset("utf-8")).generate()
+ );
+ }
+
+ void testInternationalizedEmail_nonUTF8() {
+
+ vmime::generationContext ctx(vmime::generationContext::getDefaultContext());
+ ctx.setInternationalizedEmailSupport(true);
+
+ vmime::generationContext::switcher <vmime::generationContext> contextSwitcher(ctx);
+
+ // Non UTF-8 encoded text should first be converted to UTF-8
+ VASSERT_EQ(
+ "1", "Achim Br\xc3\xa4ndt",
+ vmime::word("Achim Br\xe4ndt", vmime::charset("iso-8859-1")).generate()
+ );
+ }
+
+ void testInternationalizedEmail_folding() {
+
+ vmime::generationContext ctx(vmime::generationContext::getDefaultContext());
+ ctx.setInternationalizedEmailSupport(true);
+
+ vmime::generationContext::switcher <vmime::generationContext> contextSwitcher(ctx);
+
+ // RFC-2047 encoding must be performed, as line folding is needed
+ vmime::word w1("01234567890123456789\xc3\xa0x012345678901234567890123456789"
+ "01234567890123456789\xc3\xa0x012345678901234567890123456789", vmime::charset("utf-8"));
+
+ VASSERT_EQ(
+ "1",
+ "=?utf-8?Q?01234567890123456789=C3=A0x01234567890?=\r\n"
+ " =?utf-8?Q?1234567890123456789012345678901234567?=\r\n"
+ " =?utf-8?Q?89=C3=A0x0123456789012345678901234567?=\r\n"
+ " =?utf-8?Q?89?=",
+ w1.generate(50)
+ );
+
+ // RFC-2047 encoding will not be forced, as words can be wrapped in a new line
+ vmime::word w2("bla bla bla This is some '\xc3\xa0\xc3\xa7' UTF-8 encoded text", vmime::charset("utf-8"));
+
+ VASSERT_EQ(
+ "2",
+ "bla bla bla This is\r\n"
+ " some '\xc3\xa0\xc3\xa7' UTF-8\r\n"
+ " encoded text",
+ w2.generate(20)
+ );
+ }
+
+ void testInternationalizedEmail_whitespace() {
+
+ // Sanity checks for running this test
+ {
+ vmime::text t;
+ t.parse("=?utf-8?Q?Adquisi=C3=B3n?= de Laptop y celular");
+
+ VASSERT_EQ("parse", "Adquisión de Laptop y celular", t.getWholeBuffer());
+ }
+
+ {
+ vmime::text t("Adquisi\xc3\xb3n de Laptop y celular", vmime::charset("UTF-8"));
+
+ VASSERT_EQ("generate", "=?UTF-8?Q?Adquisi=C3=B3n?= de Laptop y celular", t.generate());
+ }
+
+ // Ensure a whitespace is added between encoded words in intl email support enabled
+ {
+ vmime::text t;
+ t.parse("=?utf-8?Q?Adquisi=C3=B3n?= de Laptop y celular");
+
+ std::ostringstream oss;
+ vmime::utility::outputStreamAdapter ossAdapter(oss);
+ vmime::generationContext gctx(vmime::generationContext::getDefaultContext());
+ gctx.setInternationalizedEmailSupport(true);
+ t.generate(gctx, ossAdapter);
+
+ VASSERT_EQ("generate", "Adquisi\xc3\xb3n de Laptop y celular", oss.str());
+ }
+
+ {
+ vmime::text t;
+ t.parse("=?utf-8?Q?Adquisi=C3=B3n?= de Laptop =?utf-8?Q?y?= celular");
+
+ std::ostringstream oss;
+ vmime::utility::outputStreamAdapter ossAdapter(oss);
+ vmime::generationContext gctx(vmime::generationContext::getDefaultContext());
+ gctx.setInternationalizedEmailSupport(true);
+ t.generate(gctx, ossAdapter);
+
+ VASSERT_EQ("generate", "Adquisi\xc3\xb3n de Laptop y celular", oss.str());
+ }
+
+ {
+ vmime::text t;
+ t.parse("=?utf-8?Q?Adquisi=C3=B3n?= de Laptop =?utf-8?Q?y_celular?=");
+
+ std::ostringstream oss;
+ vmime::utility::outputStreamAdapter ossAdapter(oss);
+ vmime::generationContext gctx(vmime::generationContext::getDefaultContext());
+ gctx.setInternationalizedEmailSupport(true);
+ t.generate(gctx, ossAdapter);
+
+ VASSERT_EQ("generate", "Adquisi\xc3\xb3n de Laptop y celular", oss.str());
+ }
+
+ // Ensure no whitespace is added with non-encoded words
+ {
+ vmime::text t;
+ t.parse("Laptop y celular");
+
+ std::ostringstream oss;
+ vmime::utility::outputStreamAdapter ossAdapter(oss);
+ vmime::generationContext gctx(vmime::generationContext::getDefaultContext());
+ gctx.setInternationalizedEmailSupport(true);
+ t.generate(gctx, ossAdapter);
+
+ VASSERT_EQ("generate", "Laptop y celular", oss.str());
+ }
+
+ {
+ vmime::text t;
+ t.parse("=?utf-8?Q?Laptop_y_celular?=");
+
+ std::ostringstream oss;
+ vmime::utility::outputStreamAdapter ossAdapter(oss);
+ vmime::generationContext gctx(vmime::generationContext::getDefaultContext());
+ gctx.setInternationalizedEmailSupport(true);
+ t.generate(gctx, ossAdapter);
+
+ VASSERT_EQ("generate", "Laptop y celular", oss.str());
+ }
+ }
+
+ void testWronglyPaddedB64Words() {
+
+ vmime::text outText;
+
+ vmime::text::decodeAndUnfold("=?utf-8?B?5Lit5?=\n =?utf-8?B?paH?=", &outText);
+
+ VASSERT_EQ(
+ "1",
+ "\xe4\xb8\xad\xe6\x96\x87",
+ outText.getConvertedText(vmime::charset("utf-8"))
+ );
+
+ vmime::text::decodeAndUnfold("=?utf-8?B?5Lit5p?=\n =?utf-8?B?aH?=", &outText);
+
+ VASSERT_EQ(
+ "2",
+ "\xe4\xb8\xad\xe6\x96\x87",
+ outText.getConvertedText(vmime::charset("utf-8"))
+ );
+
+ vmime::text::decodeAndUnfold("=?utf-8?B?5Lit5pa?=\n =?utf-8?B?H?=", &outText);
+
+ VASSERT_EQ(
+ "3",
+ "\xe4\xb8\xad\xe6\x96\x87",
+ outText.getConvertedText(vmime::charset("utf-8"))
+ );
+ }
+
+ // Ensure that words which encode a non-integral number of characters
+ // are correctly decoded.
+ void testFixBrokenWords() {
+
+ vmime::text outText;
+
+ vmime::charsetConverterOptions opts;
+ opts.silentlyReplaceInvalidSequences = false; // just to be sure that broken words are actually fixed
+
+ // Test case 1
+ vmime::text::decodeAndUnfold(
+ "=?utf-8?Q?Gwena=C3?="
+ "=?utf-8?Q?=ABl?=",
+ &outText
+ );
+
+ VASSERT_EQ("1.1", 1, outText.getWordCount());
+ VASSERT_EQ("1.2", "Gwena\xc3\xabl", outText.getWordAt(0)->getBuffer());
+ VASSERT_EQ("1.3", vmime::charset("utf-8"), outText.getWordAt(0)->getCharset());
+
+ // Test case 2
+ vmime::text::decodeAndUnfold(
+ "=?utf-8?B?5Lit6Yu85qmf5qKw6JGj5LqL5pyDMTAz5bm056ysMDXlsYbn?="
+ "=?utf-8?B?rKwwN+asoeitsOeoiw==?=",
+ &outText
+ );
+
+ VASSERT_EQ("2.1", 1, outText.getWordCount());
+ VASSERT_EQ("2.2", "\xe4\xb8\xad\xe9\x8b\xbc\xe6\xa9\x9f\xe6\xa2\xb0"
+ "\xe8\x91\xa3\xe4\xba\x8b\xe6\x9c\x83\x31\x30\x33\xe5\xb9\xb4"
+ "\xe7\xac\xac\x30\x35\xe5\xb1\x86\xe7\xac\xac\x30\x37\xe6\xac"
+ "\xa1\xe8\xad\xb0\xe7\xa8\x8b", outText.getWordAt(0)->getBuffer());
+ VASSERT_EQ("2.3", vmime::charset("utf-8"), outText.getWordAt(0)->getCharset());
+
+ // Test case 3 (a character spanning over 3 words: 'を' = E3 82 92)
+ vmime::text::decodeAndUnfold(
+ "=?utf-8?Q?abc=E3?="
+ "=?utf-8?Q?=82?="
+ "=?utf-8?Q?=92xyz?=",
+ &outText
+ );
+
+ VASSERT_EQ("3.1", 1, outText.getWordCount());
+ VASSERT_EQ("3.2", "abc\xe3\x82\x92xyz", outText.getWordAt(0)->getBuffer());
+ VASSERT_EQ("3.3", vmime::charset("utf-8"), outText.getWordAt(0)->getCharset());
+
+ // Test case 4 (remains invalid)
+ vmime::text::decodeAndUnfold(
+ "=?utf-8?Q?abc=E3?="
+ "=?utf-8?Q?=82?="
+ "=?utf-8?Q?xy?="
+ "=?utf-8?Q?z?=",
+ &outText
+ );
+
+ VASSERT_EQ("4.1", 2, outText.getWordCount());
+ VASSERT_EQ("4.2", "abc", outText.getWordAt(0)->getBuffer());
+ VASSERT_EQ("4.3", vmime::charset("utf-8"), outText.getWordAt(0)->getCharset());
+ VASSERT_EQ("4.4", "\xe3\x82xyz", outText.getWordAt(1)->getBuffer());
+ VASSERT_EQ("4.5", vmime::charset("utf-8"), outText.getWordAt(1)->getCharset());
+
+ // Test case 5 (remains partially invalid)
+ vmime::text::decodeAndUnfold(
+ "=?utf-8?Q?abc=E3?="
+ "=?utf-8?Q?=82?="
+ "=?utf-8?Q?\x92xy?="
+ "=?utf-8?Q?z\xc3?=",
+ &outText
+ );
+
+ VASSERT_EQ("5.1", 2, outText.getWordCount());
+ VASSERT_EQ("5.2", "abc\xe3\x82\x92xyz", outText.getWordAt(0)->getBuffer());
+ VASSERT_EQ("5.3", vmime::charset("utf-8"), outText.getWordAt(0)->getCharset());
+ VASSERT_EQ("5.4", "\xc3", outText.getWordAt(1)->getBuffer());
+ VASSERT_EQ("5.5", vmime::charset("utf-8"), outText.getWordAt(1)->getCharset());
+ }
+
+ void testUnknownCharset() {
+
+ vmime::text t;
+ vmime::text::decodeAndUnfold("=?gb2312?B?wdaRY8PA?=", &t);
+
+ VASSERT_EQ("1.1", 1, t.getWordCount());
+ VASSERT_EQ("1.2", "\xc1\xd6\x91\x63\xc3\xc0", t.getWordAt(0)->getBuffer());
+ VASSERT_EQ("1.3", vmime::charset("gb2312"), t.getWordAt(0)->getCharset());
+
+
+
+ vmime::parsingContext ctx;
+
+ const vmime::string hfieldBuffer = "From: '=?gb2312?B?wdaRY8PA?=' <a.b@c.de>";
+
+ vmime::shared_ptr <vmime::headerField> hfield =
+ vmime::headerField::parseNext(ctx, hfieldBuffer, 0, hfieldBuffer.size());
+
+ vmime::shared_ptr <vmime::mailbox> hvalue =
+ hfield->getValue <vmime::mailbox>();
+
+ VASSERT_EQ("2.1", 3, hvalue->getName().getWordCount());
+ VASSERT_EQ("2.2", "'", hvalue->getName().getWordAt(0)->getBuffer());
+ VASSERT_EQ("2.3", vmime::charset("us-ascii"), hvalue->getName().getWordAt(0)->getCharset());
+ VASSERT_EQ("2.4", "\xc1\xd6\x91\x63\xc3\xc0", hvalue->getName().getWordAt(1)->getBuffer());
+ VASSERT_EQ("2.5", vmime::charset("gb2312"), hvalue->getName().getWordAt(1)->getCharset());
+ VASSERT_EQ("2.6", "'", hvalue->getName().getWordAt(2)->getBuffer());
+ VASSERT_EQ("2.7", vmime::charset("us-ascii"), hvalue->getName().getWordAt(2)->getCharset());
+ }
+
+VMIME_TEST_SUITE_END
diff --git a/vmime-master/tests/parser/wordEncoderTest.cpp b/vmime-master/tests/parser/wordEncoderTest.cpp
new file mode 100644
index 0000000..08d34aa
--- /dev/null
+++ b/vmime-master/tests/parser/wordEncoderTest.cpp
@@ -0,0 +1,174 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "tests/testUtils.hpp"
+
+#include "vmime/wordEncoder.hpp"
+
+
+VMIME_TEST_SUITE_BEGIN(wordEncoderTest)
+
+ VMIME_TEST_LIST_BEGIN
+ VMIME_TEST(testGetNextChunk)
+ VMIME_TEST(testGetNextChunk_integral)
+ VMIME_TEST(testIsEncodingNeeded_ascii)
+ VMIME_TEST(testIsEncodingNeeded_withLanguage)
+ VMIME_TEST(testIsEncodingNeeded_specialChars)
+ VMIME_TEST(testGuessBestEncoding_QP)
+ VMIME_TEST(testGuessBestEncoding_B64)
+ VMIME_TEST(testEncodeQP_RFC2047)
+ VMIME_TEST_LIST_END
+
+
+ void testGetNextChunk() {
+
+ // An integral number of characters should be encoded
+ vmime::wordEncoder we(
+ "bufferfoobarbaz",
+ vmime::charset("utf-8"),
+ vmime::wordEncoder::ENCODING_AUTO
+ );
+
+ VASSERT_EQ("1", "buffer", we.getNextChunk(6));
+ VASSERT_EQ("2", "foo", we.getNextChunk(3));
+ VASSERT_EQ("3", "barbaz", we.getNextChunk(10));
+ }
+
+ void testGetNextChunk_integral() {
+
+ // An integral number of characters should be encoded
+ vmime::wordEncoder we(
+ "buffer\xc3\xa0plop",
+ vmime::charset("utf-8"),
+ vmime::wordEncoder::ENCODING_AUTO
+ );
+
+ VASSERT_EQ("1", "buffer=C3=A0", we.getNextChunk(7));
+ VASSERT_EQ("2", "plop", we.getNextChunk(10));
+ }
+
+ void testIsEncodingNeeded_ascii() {
+
+ vmime::generationContext ctx(vmime::generationContext::getDefaultContext());
+ ctx.setInternationalizedEmailSupport(false);
+
+ VASSERT_FALSE(
+ "ascii",
+ vmime::wordEncoder::isEncodingNeeded(
+ ctx, "ASCII-only buffer", vmime::charset("utf-8"), ""
+ )
+ );
+
+ VASSERT_TRUE(
+ "non-ascii",
+ vmime::wordEncoder::isEncodingNeeded(
+ ctx, "Buffer with some UTF-8 '\xc3\xa0'", vmime::charset("utf-8"), ""
+ )
+ );
+ }
+
+ void testIsEncodingNeeded_withLanguage() {
+
+ VASSERT_TRUE(
+ "ascii",
+ vmime::wordEncoder::isEncodingNeeded(
+ vmime::generationContext::getDefaultContext(),
+ "ASCII-only buffer",
+ vmime::charset("utf-8"),
+ "en"
+ )
+ );
+ }
+
+ void testIsEncodingNeeded_specialChars() {
+
+ VASSERT_TRUE(
+ "rfc2047",
+ vmime::wordEncoder::isEncodingNeeded(
+ vmime::generationContext::getDefaultContext(),
+ "foo bar =? foo bar",
+ vmime::charset("us-ascii"),
+ ""
+ )
+ );
+
+ VASSERT_TRUE(
+ "new line 1",
+ vmime::wordEncoder::isEncodingNeeded(
+ vmime::generationContext::getDefaultContext(),
+ "foo bar \n foo bar",
+ vmime::charset("us-ascii"),
+ ""
+ )
+ );
+
+ VASSERT_TRUE(
+ "new line 2",
+ vmime::wordEncoder::isEncodingNeeded(
+ vmime::generationContext::getDefaultContext(),
+ "foo bar \r foo bar",
+ vmime::charset("us-ascii"),
+ ""
+ )
+ );
+ }
+
+ void testGuessBestEncoding_QP() {
+
+ VASSERT_EQ(
+ "1",
+ vmime::wordEncoder::ENCODING_QP,
+ vmime::wordEncoder::guessBestEncoding("ASCII only buffer", vmime::charset("us-ascii"))
+ );
+ }
+
+ void testGuessBestEncoding_B64() {
+
+ // >= 40% non-ASCII => Base64...
+ VASSERT_EQ(
+ "1",
+ vmime::wordEncoder::ENCODING_B64,
+ vmime::wordEncoder::guessBestEncoding("xxxxx\xc3\xa0\xc3\xa0", vmime::charset("utf-8"))
+ );
+
+ // ...else Quoted-Printable
+ VASSERT_EQ(
+ "2",
+ vmime::wordEncoder::ENCODING_QP,
+ vmime::wordEncoder::guessBestEncoding("xxxxxx\xc3\xa0\xc3\xa0", vmime::charset("utf-8"))
+ );
+ }
+
+ void testEncodeQP_RFC2047() {
+
+ // When Quoted-Printable is used, it should be RFC-2047 QP encoding
+ vmime::wordEncoder we(
+ "buffer\xc3\xa0 foo_bar",
+ vmime::charset("utf-8"),
+ vmime::wordEncoder::ENCODING_AUTO
+ );
+
+ VASSERT_EQ("1", "buffer=C3=A0_foo=5Fbar", we.getNextChunk(100));
+ }
+
+VMIME_TEST_SUITE_END
diff --git a/vmime-master/tests/security/digest/md5Test.cpp b/vmime-master/tests/security/digest/md5Test.cpp
new file mode 100644
index 0000000..ca6d3d4
--- /dev/null
+++ b/vmime-master/tests/security/digest/md5Test.cpp
@@ -0,0 +1,228 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "tests/testUtils.hpp"
+
+#include "vmime/security/digest/messageDigestFactory.hpp"
+
+
+#define INIT_DIGEST(var, algo) \
+ vmime::shared_ptr <vmime::security::digest::messageDigest> var = \
+ vmime::security::digest::messageDigestFactory::getInstance()->create(algo)
+
+
+
+VMIME_TEST_SUITE_BEGIN(md5Test)
+
+ VMIME_TEST_LIST_BEGIN
+ VMIME_TEST(testRFC1321_1)
+ VMIME_TEST(testRFC1321_2)
+ VMIME_TEST(testRFC1321_3)
+ VMIME_TEST(testRFC1321_4)
+ VMIME_TEST(testRFC1321_5)
+ VMIME_TEST(testRFC1321_6)
+ VMIME_TEST(testRFC1321_7)
+ VMIME_TEST(testUpdate1)
+ VMIME_TEST(testUpdate2)
+ VMIME_TEST(testUpdate3)
+ VMIME_TEST(testUpdate4)
+ VMIME_TEST(testUpdate5)
+ VMIME_TEST(testUpdate6)
+ VMIME_TEST(testUpdate7)
+ VMIME_TEST_LIST_END
+
+
+ // Test suites from RFC #1321
+
+ void testRFC1321_1() {
+
+ INIT_DIGEST(algo, "md5");
+
+ algo->update("");
+ algo->finalize();
+
+ VASSERT_EQ("*", "d41d8cd98f00b204e9800998ecf8427e", algo->getHexDigest());
+ }
+
+ void testRFC1321_2() {
+
+ INIT_DIGEST(algo, "md5");
+
+ algo->update("a");
+ algo->finalize();
+
+ VASSERT_EQ("*", "0cc175b9c0f1b6a831c399e269772661", algo->getHexDigest());
+ }
+
+ void testRFC1321_3() {
+
+ INIT_DIGEST(algo, "md5");
+
+ algo->update("abc");
+ algo->finalize();
+
+ VASSERT_EQ("*", "900150983cd24fb0d6963f7d28e17f72", algo->getHexDigest());
+ }
+
+ void testRFC1321_4() {
+
+ INIT_DIGEST(algo, "md5");
+
+ algo->update("message digest");
+ algo->finalize();
+
+ VASSERT_EQ("*", "f96b697d7cb7938d525a2f31aaf161d0", algo->getHexDigest());
+ }
+
+ void testRFC1321_5() {
+
+ INIT_DIGEST(algo, "md5");
+
+ algo->update("abcdefghijklmnopqrstuvwxyz");
+ algo->finalize();
+
+ VASSERT_EQ("*", "c3fcd3d76192e4007dfb496cca67e13b", algo->getHexDigest());
+ }
+
+ void testRFC1321_6() {
+
+ INIT_DIGEST(algo, "md5");
+
+ algo->update("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789");
+ algo->finalize();
+
+ VASSERT_EQ("*", "d174ab98d277d9f5a5611c2c9f419d9f", algo->getHexDigest());
+ }
+
+ void testRFC1321_7() {
+
+ INIT_DIGEST(algo, "md5");
+
+ algo->update("12345678901234567890123456789012345678901234567890123456789012345678901234567890");
+ algo->finalize();
+
+ VASSERT_EQ("*", "57edf4a22be3c955ac49da2e2107b67a", algo->getHexDigest());
+ }
+
+ void testReset() {
+
+ INIT_DIGEST(algo, "md5");
+
+ algo->update("foo");
+ algo->update("bar");
+ algo->finalize();
+
+ algo->reset();
+ algo->finalize();
+
+ VASSERT_EQ("*", "d41d8cd98f00b204e9800998ecf8427e", algo->getHexDigest()); // empty string
+ }
+
+ void testUpdate1() {
+
+ INIT_DIGEST(algo, "md5");
+
+ algo->update("");
+ algo->finalize();
+
+ VASSERT_EQ("*", "d41d8cd98f00b204e9800998ecf8427e", algo->getHexDigest());
+ }
+
+ void testUpdate2() {
+
+ INIT_DIGEST(algo, "md5");
+
+ algo->update("a");
+ algo->update("");
+ algo->finalize();
+
+ VASSERT_EQ("2", "0cc175b9c0f1b6a831c399e269772661", algo->getHexDigest());
+ }
+
+ void testUpdate3() {
+
+ INIT_DIGEST(algo, "md5");
+
+ algo->update("ab");
+ algo->update("c");
+ algo->finalize();
+
+ VASSERT_EQ("3", "900150983cd24fb0d6963f7d28e17f72", algo->getHexDigest());
+ }
+
+ void testUpdate4() {
+
+ INIT_DIGEST(algo, "md5");
+
+ algo->update("");
+ algo->update("message");
+ algo->update(" ");
+ algo->update("digest");
+ algo->finalize();
+
+ VASSERT_EQ("4", "f96b697d7cb7938d525a2f31aaf161d0", algo->getHexDigest());
+ }
+
+ void testUpdate5() {
+
+ INIT_DIGEST(algo, "md5");
+
+ algo->update("abcd");
+ algo->update("");
+ algo->update("efghijklmnop");
+ algo->update("qrstuvwx");
+ algo->update("yz");
+ algo->finalize();
+
+ VASSERT_EQ("5", "c3fcd3d76192e4007dfb496cca67e13b", algo->getHexDigest());
+ }
+
+ void testUpdate6() {
+
+ INIT_DIGEST(algo, "md5");
+
+ algo->update("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz012");
+ algo->update("345");
+ algo->update("6");
+ algo->update("7");
+ algo->update("89");
+ algo->finalize();
+
+ VASSERT_EQ("6", "d174ab98d277d9f5a5611c2c9f419d9f", algo->getHexDigest());
+ }
+
+ void testUpdate7() {
+
+ INIT_DIGEST(algo, "md5");
+
+ algo->update("12345678901234567890123456789");
+ algo->update("01234567890123456789012345678901");
+ algo->update("234567890123456789");
+ algo->update("");
+ algo->update("0");
+ algo->finalize();
+
+ VASSERT_EQ("7", "57edf4a22be3c955ac49da2e2107b67a", algo->getHexDigest());
+ }
+
+VMIME_TEST_SUITE_END
diff --git a/vmime-master/tests/security/digest/sha1Test.cpp b/vmime-master/tests/security/digest/sha1Test.cpp
new file mode 100644
index 0000000..cbcd1cf
--- /dev/null
+++ b/vmime-master/tests/security/digest/sha1Test.cpp
@@ -0,0 +1,119 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "tests/testUtils.hpp"
+
+#include "vmime/security/digest/messageDigestFactory.hpp"
+
+
+#define INIT_DIGEST(var, algo) \
+ vmime::shared_ptr <vmime::security::digest::messageDigest> var = \
+ vmime::security::digest::messageDigestFactory::getInstance()->create(algo)
+
+
+
+VMIME_TEST_SUITE_BEGIN(sha1Test)
+
+ VMIME_TEST_LIST_BEGIN
+ VMIME_TEST(testFIPS180_1)
+ VMIME_TEST(testFIPS180_2)
+ VMIME_TEST(testFIPS180_3)
+ VMIME_TEST(testReset)
+ VMIME_TEST(testUpdate)
+ VMIME_TEST_LIST_END
+
+
+ // Test suites from FIPS PUB 180-1
+ // http://www.itl.nist.gov/fipspubs/fip180-1.htm
+
+ void testFIPS180_1() {
+
+ INIT_DIGEST(algo, "sha1");
+
+ algo->update("abc");
+ algo->finalize();
+
+ VASSERT_EQ("*", "a9993e364706816aba3e25717850c26c9cd0d89d", algo->getHexDigest());
+ }
+
+ void testFIPS180_2() {
+
+ INIT_DIGEST(algo, "sha1");
+
+ algo->update("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq");
+ algo->finalize();
+
+ VASSERT_EQ("*", "84983e441c3bd26ebaae4aa1f95129e5e54670f1", algo->getHexDigest());
+ }
+
+ void testFIPS180_3() {
+
+ INIT_DIGEST(algo, "sha1");
+
+ vmime::byte_t* buffer = new vmime::byte_t[1000000];
+
+ for (int i = 0 ; i < 1000000 ; ++i) {
+ buffer[i] = 'a';
+ }
+
+ algo->update(buffer, 1000000);
+ algo->finalize();
+
+ delete [] buffer;
+
+ VASSERT_EQ("*", "34aa973cd4c4daa4f61eeb2bdbad27316534016f", algo->getHexDigest());
+ }
+
+ void testReset() {
+
+ INIT_DIGEST(algo, "sha1");
+
+ algo->update("ab");
+ algo->update("c");
+ algo->finalize();
+
+ algo->reset();
+ algo->finalize();
+
+ VASSERT_EQ("*", "da39a3ee5e6b4b0d3255bfef95601890afd80709", algo->getHexDigest()); // empty string
+ }
+
+ void testUpdate() {
+
+ INIT_DIGEST(algo, "sha1");
+
+ algo->update("a");
+ algo->update("");
+ algo->update("bcdbcdecdefd");
+ algo->update("efgef");
+ algo->update("ghfghighijhijkijkljklmklmnlmnomnopnop");
+ algo->update("");
+ algo->update("q");
+ algo->update("");
+ algo->update("");
+ algo->finalize();
+
+ VASSERT_EQ("*", "84983e441c3bd26ebaae4aa1f95129e5e54670f1", algo->getHexDigest());
+ }
+
+VMIME_TEST_SUITE_END
diff --git a/vmime-master/tests/testRunner.cpp b/vmime-master/tests/testRunner.cpp
new file mode 100644
index 0000000..f1f13b2
--- /dev/null
+++ b/vmime-master/tests/testRunner.cpp
@@ -0,0 +1,305 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include <sys/time.h>
+#include <time.h>
+
+#include <iostream>
+#include <vector>
+#include <algorithm>
+#include <memory>
+
+#include <cppunit/XmlOutputter.h>
+#include <cppunit/extensions/TestFactoryRegistry.h>
+#include <cppunit/ui/text/TestRunner.h>
+#include <cppunit/TestListener.h>
+#include <cppunit/TestResult.h>
+#include <cppunit/TestResultCollector.h>
+#include <cppunit/TestFailure.h>
+#include <cppunit/SourceLine.h>
+#include <cppunit/Exception.h>
+#include <cppunit/tools/XmlDocument.h>
+#include <cppunit/tools/XmlElement.h>
+
+#include "vmime/vmime.hpp"
+#include "vmime/platforms/posix/posixHandler.hpp"
+
+
+class Clock {
+
+public:
+
+ void reset() {
+
+ struct timezone tz;
+
+ gettimeofday(&m_start, &tz);
+ }
+
+ double getDuration() const {
+
+ struct timeval tv;
+ struct timezone tz;
+
+ gettimeofday(&tv, &tz);
+
+ return static_cast <double>(tv.tv_sec - m_start.tv_sec)
+ + static_cast <double>(tv.tv_usec - m_start.tv_usec) / 1000000.0;
+ }
+
+private:
+
+ struct timeval m_start;
+};
+
+
+class XmlTestListener : public CppUnit::TestListener {
+
+public:
+
+ XmlTestListener()
+ : m_doc("utf-8"),
+ m_testElt(NULL) {
+
+ m_doc.setRootElement(new CppUnit::XmlElement("TestRun"));
+ }
+
+ void startTest(CppUnit::Test* test) {
+
+ m_testElt = new CppUnit::XmlElement("Test");
+ m_suiteElt.back()->addElement(m_testElt);
+
+ m_testElt->addElement(new CppUnit::XmlElement("Name", test->getName()));
+
+ m_chrono.reset();
+ }
+
+ void addFailure(const CppUnit::TestFailure& failure) {
+
+ CppUnit::XmlElement* failElt = new CppUnit::XmlElement("Failure");
+ m_testElt->addElement(failElt);
+
+ failElt->addElement(
+ new CppUnit::XmlElement("FailureType", failure.isError() ? "Error" : "Assertion")
+ );
+
+ if (failure.sourceLine().isValid()) {
+
+ CppUnit::XmlElement* locElt = new CppUnit::XmlElement("Location");
+ failElt->addElement(locElt);
+
+ locElt->addElement(new CppUnit::XmlElement("File", failure.sourceLine().fileName()));
+ locElt->addElement(new CppUnit::XmlElement("Line", failure.sourceLine().lineNumber()));
+ }
+
+ CppUnit::XmlElement* exElt = new CppUnit::XmlElement("Exception");
+ failElt->addElement(exElt);
+
+ exElt->addElement(new CppUnit::XmlElement("Message", failure.thrownException()->what()));
+ }
+
+ void endTest(CppUnit::Test* /* test */) {
+
+ std::ostringstream ossTime;
+ ossTime << (m_chrono.getDuration() * 1000.0);
+
+ m_testElt->addElement(new CppUnit::XmlElement("Time", ossTime.str()));
+
+ m_testElt = NULL;
+ }
+
+ void startSuite(CppUnit::Test* suite) {
+
+ if (suite->getName() == "All Tests") {
+ return;
+ }
+
+ CppUnit::XmlElement* suiteElt = new CppUnit::XmlElement("Suite");
+
+ if (m_suiteElt.size() == 0) {
+ m_doc.rootElement().addElement(suiteElt);
+ } else {
+ m_suiteElt.back()->addElement(suiteElt);
+ }
+
+ m_suiteElt.push_back(suiteElt);
+
+ suiteElt->addElement(new CppUnit::XmlElement("Name", suite->getName()));
+ }
+
+ void endSuite(CppUnit::Test* /* suite */) {
+
+ if (m_suiteElt.size()) {
+ m_suiteElt.pop_back();
+ }
+ }
+
+ void startTestRun(CppUnit::Test* /* test */, CppUnit::TestResult* /* eventManager */) {
+
+ }
+
+ void endTestRun(CppUnit::Test* /* test */, CppUnit::TestResult* /* eventManager */) {
+
+ }
+
+ void output(std::ostream& os) {
+
+ os << m_doc.toString();
+ }
+
+private:
+
+ Clock m_chrono;
+
+ CppUnit::XmlDocument m_doc;
+ std::vector <CppUnit::XmlElement*> m_suiteElt;
+ CppUnit::XmlElement* m_testElt;
+};
+
+
+
+// see testUtils.hpp
+
+std::vector <std::string>& getTestModules() {
+
+ static std::vector <std::string> allModules;
+ return allModules;
+}
+
+
+void registerTestModule(const char* name_) {
+
+ std::vector <std::string>& testModules = getTestModules();
+ std::string name(name_);
+
+ if (std::find(testModules.begin(), testModules.end(), name) == testModules.end()) {
+ testModules.push_back(name);
+ }
+}
+
+
+const std::string getNormalizedPath(const std::string& path) {
+
+ std::string res = path;
+
+ for (std::size_t i = 0, n = res.length() ; i < n ; ++i) {
+
+ if (res[i] == '\\') {
+ res[i] = '/';
+ }
+ }
+
+ return res;
+}
+
+
+const std::string getFileNameFromPath(const std::string& path) {
+
+ const std::size_t pos = path.find_last_of('/');
+
+ if (pos == std::string::npos) {
+ return "";
+ }
+
+ return path.substr(pos + 1);
+}
+
+
+static char g_moduleNameBuffer[2048];
+
+
+const char* getTestModuleNameFromSourceFile(const char *path_) {
+
+ static const std::string testRunnerPath(getNormalizedPath(__FILE__));
+ static const std::string testRunnerFileName(getFileNameFromPath(testRunnerPath));
+
+ const std::string path = getNormalizedPath(path_);
+
+ // "/path/to/testRunner.cpp" --> "/path/to/"
+ const std::string basePath
+ (testRunnerPath.begin(), testRunnerPath.end() - testRunnerFileName.length());
+
+ // "/path/to/module/testFile.cpp" --> "module/testFile.cpp"
+ const std::string testFileName(getFileNameFromPath(path));
+ const std::string testPath(path.begin() + basePath.length(), path.end());
+
+ // "module/testFile.cpp" --> "module"
+ const std::string moduleName(testPath.substr(0, testPath.length() - testFileName.length() - 1));
+ std::copy(moduleName.begin(), moduleName.end(), g_moduleNameBuffer);
+ g_moduleNameBuffer[moduleName.length()] = 0;
+
+ return g_moduleNameBuffer;
+}
+
+
+int main(int argc, char* argv[]) {
+
+ // Parse arguments
+ bool xmlOutput = false;
+
+ for (int c = 1 ; c < argc ; ++c) {
+
+ const std::string arg = argv[c];
+
+ if (arg == "--xml") {
+ xmlOutput = true;
+ }
+ }
+
+ // Run the tests
+ if (xmlOutput) {
+
+ // Get the test suites from the registry and add them to the list of tests to run
+ CppUnit::TestRunner runner;
+
+ for (unsigned int i = 0 ; i < getTestModules().size() ; ++i) {
+
+ runner.addTest(
+ CppUnit::TestFactoryRegistry::getRegistry(getTestModules()[i]).makeTest()
+ );
+ }
+
+ XmlTestListener xmlListener;
+
+ CppUnit::TestResult controller;
+ controller.addListener(&xmlListener);
+
+ CppUnit::TestResultCollector result;
+ controller.addListener(&result);
+
+ runner.run(controller);
+
+ xmlListener.output(std::cout);
+
+ // Return error code 1 if a test failed
+ return result.wasSuccessful() ? 0 : 1;
+
+ } else {
+
+ // Get the top level suite from the registry
+ CppUnit::TextUi::TestRunner runner;
+ runner.addTest(CppUnit::TestFactoryRegistry::getRegistry().makeTest());
+
+ return runner.run() ? 0 : 1;
+ }
+}
diff --git a/vmime-master/tests/testUtils.cpp b/vmime-master/tests/testUtils.cpp
new file mode 100644
index 0000000..ae75547
--- /dev/null
+++ b/vmime-master/tests/testUtils.cpp
@@ -0,0 +1,404 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "testUtils.hpp"
+
+#include "vmime/utility/stringUtils.hpp"
+
+#include <cstring>
+#include <iostream>
+
+
+// Enable to output socket send/receive on standard output
+#define DEBUG_SOCKET_IN_OUT 0
+
+
+
+// testSocket
+
+void testSocket::connect(const vmime::string& address, const vmime::port_t port) {
+
+ m_address = address;
+ m_port = port;
+ m_connected = true;
+
+ onConnected();
+}
+
+
+void testSocket::disconnect() {
+
+ m_address.clear();
+ m_port = 0;
+ m_connected = false;
+}
+
+
+bool testSocket::isConnected() const {
+
+ return m_connected;
+}
+
+
+vmime::size_t testSocket::getBlockSize() const {
+
+ return 16384;
+}
+
+
+unsigned int testSocket::getStatus() const {
+
+ return 0;
+}
+
+
+const vmime::string testSocket::getPeerName() const {
+
+ return "test.vmime.org";
+}
+
+
+const vmime::string testSocket::getPeerAddress() const {
+
+ return "127.0.0.1";
+}
+
+
+vmime::shared_ptr <vmime::net::timeoutHandler> testSocket::getTimeoutHandler() {
+
+ return vmime::null;
+}
+
+
+void testSocket::setTracer(const vmime::shared_ptr <vmime::net::tracer>& /* tracer */) {
+
+}
+
+
+vmime::shared_ptr <vmime::net::tracer> testSocket::getTracer() {
+
+ return vmime::null;
+}
+
+
+bool testSocket::waitForRead(const int /* msecs */) {
+
+ return true;
+}
+
+
+bool testSocket::waitForWrite(const int /* msecs */) {
+
+ return true;
+}
+
+
+void testSocket::receive(vmime::string& buffer) {
+
+ buffer = m_inBuffer;
+ m_inBuffer.clear();
+}
+
+
+void testSocket::send(const vmime::string& buffer) {
+
+ m_outBuffer += buffer;
+
+ onDataReceived();
+}
+
+
+void testSocket::send(const char* str) {
+
+ sendRaw(reinterpret_cast <const vmime::byte_t*>(str), strlen(str));
+}
+
+
+vmime::size_t testSocket::receiveRaw(vmime::byte_t* buffer, const size_t count) {
+
+ const size_t n = std::min(count, static_cast <size_t>(m_inBuffer.size()));
+
+ std::copy(m_inBuffer.begin(), m_inBuffer.begin() + n, buffer);
+ m_inBuffer.erase(m_inBuffer.begin(), m_inBuffer.begin() + n);
+
+ return n;
+}
+
+
+void testSocket::sendRaw(const vmime::byte_t* buffer, const size_t count) {
+
+ send(vmime::utility::stringUtils::makeStringFromBytes(buffer, count));
+}
+
+
+vmime::size_t testSocket::sendRawNonBlocking(const vmime::byte_t* buffer, const size_t count) {
+
+ sendRaw(buffer, count);
+ return count;
+}
+
+
+void testSocket::localSend(const vmime::string& buffer) {
+
+ m_inBuffer += buffer;
+
+#if DEBUG_SOCKET_IN_OUT
+ std::cout << "> " << vmime::utility::stringUtils::trim(buffer) << std::endl;
+#endif // DEBUG_SOCKET_IN_OUT
+
+}
+
+
+void testSocket::localReceive(vmime::string& buffer) {
+
+ buffer = m_outBuffer;
+ m_outBuffer.clear();
+}
+
+
+bool testSocket::localReceiveLine(vmime::string& line) {
+
+ vmime::size_t eol;
+
+ if ((eol = m_outBuffer.find('\n')) != vmime::string::npos) {
+
+ line = vmime::string(m_outBuffer.begin(), m_outBuffer.begin() + eol);
+
+ if (!line.empty() && line[line.length() - 1] == '\r') {
+ line.erase(line.end() - 1, line.end());
+ }
+
+ m_outBuffer.erase(m_outBuffer.begin(), m_outBuffer.begin() + eol + 1);
+
+ return true;
+ }
+
+ return false;
+}
+
+
+vmime::size_t testSocket::localReceiveRaw(vmime::byte_t* buffer, const size_t count) {
+
+ const size_t received = std::min(count, static_cast <size_t>(m_outBuffer.size()));
+
+ if (received != 0) {
+
+ if (buffer) {
+ std::copy(m_outBuffer.begin(), m_outBuffer.begin() + received, buffer);
+ }
+
+ m_outBuffer.erase(m_outBuffer.begin(), m_outBuffer.begin() + received);
+ }
+
+ return received;
+}
+
+
+void testSocket::onDataReceived() {
+
+ // Override
+}
+
+
+void testSocket::onConnected() {
+
+ // Override
+}
+
+
+// lineBasedTestSocket
+
+void lineBasedTestSocket::onDataReceived() {
+
+ vmime::string chunk;
+ localReceive(chunk);
+
+ m_buffer += chunk;
+
+ vmime::size_t eol;
+
+ while ((eol = m_buffer.find('\n')) != vmime::string::npos) {
+
+ vmime::string line(std::string(m_buffer.begin(), m_buffer.begin() + eol));
+
+ if (!line.empty() && line[line.length() - 1] == '\r') {
+ line.erase(line.end() - 1, line.end());
+ }
+
+#if DEBUG_SOCKET_IN_OUT
+ std::cout << "< " << vmime::utility::stringUtils::trim(line) << std::endl;
+#endif // DEBUG_SOCKET_IN_OUT
+
+ m_lines.push_back(line);
+ m_buffer.erase(m_buffer.begin(), m_buffer.begin() + eol + 1);
+ }
+
+ while (!m_lines.empty()) {
+ processCommand();
+ }
+}
+
+
+const vmime::string lineBasedTestSocket::getNextLine() {
+
+ const vmime::string line = m_lines.front();
+ m_lines.erase(m_lines.begin(), m_lines.begin() + 1);
+ return line;
+}
+
+
+bool lineBasedTestSocket::haveMoreLines() const {
+
+ return !m_lines.empty();
+}
+
+
+// testTimeoutHandler
+
+testTimeoutHandler::testTimeoutHandler(const unsigned long delay)
+ : m_delay(delay),
+ m_start(0) {
+
+}
+
+
+bool testTimeoutHandler::isTimeOut() {
+
+ return (vmime::platform::getHandler()->getUnixTime() - m_start) >= m_delay;
+}
+
+
+void testTimeoutHandler::resetTimeOut() {
+
+ m_start = vmime::platform::getHandler()->getUnixTime();
+}
+
+
+bool testTimeoutHandler::handleTimeOut() {
+
+ return false;
+}
+
+
+// testTimeoutHandlerFactory : public vmime::net::timeoutHandlerFactory
+
+vmime::shared_ptr <vmime::net::timeoutHandler> testTimeoutHandlerFactory::create() {
+
+ return vmime::make_shared <testTimeoutHandler>();
+}
+
+
+
+// Exception helper
+std::ostream& operator<<(std::ostream& os, const vmime::exception& e) {
+
+ os << "* vmime::exceptions::" << e.name() << std::endl;
+ os << " what = " << e.what() << std::endl;
+
+ // More information for special exceptions
+ if (dynamic_cast <const vmime::exceptions::command_error*>(&e)) {
+
+ const vmime::exceptions::command_error& cee =
+ dynamic_cast <const vmime::exceptions::command_error&>(e);
+
+ os << " command = " << cee.command() << std::endl;
+ os << " response = " << cee.response() << std::endl;
+ }
+
+ if (dynamic_cast <const vmime::exceptions::invalid_response*>(&e)) {
+
+ const vmime::exceptions::invalid_response& ir =
+ dynamic_cast <const vmime::exceptions::invalid_response&>(e);
+
+ os << " response = " << ir.response() << std::endl;
+ }
+
+ if (dynamic_cast <const vmime::exceptions::connection_greeting_error*>(&e)) {
+
+ const vmime::exceptions::connection_greeting_error& cgee =
+ dynamic_cast <const vmime::exceptions::connection_greeting_error&>(e);
+
+ os << " response = " << cgee.response() << std::endl;
+ }
+
+ if (dynamic_cast <const vmime::exceptions::authentication_error*>(&e)) {
+
+ const vmime::exceptions::authentication_error& aee =
+ dynamic_cast <const vmime::exceptions::authentication_error&>(e);
+
+ os << " response = " << aee.response() << std::endl;
+ }
+
+ if (dynamic_cast <const vmime::exceptions::filesystem_exception*>(&e)) {
+
+ const vmime::exceptions::filesystem_exception& fse =
+ dynamic_cast <const vmime::exceptions::filesystem_exception&>(e);
+
+ os << " path = " << vmime::platform::getHandler()->
+ getFileSystemFactory()->pathToString(fse.path()) << std::endl;
+ }
+
+ if (e.other()) {
+ os << *e.other();
+ }
+
+ return os;
+}
+
+
+const vmime::string toHex(const vmime::string str) {
+
+ static const char hexChars[] = "0123456789abcdef";
+
+ vmime::string res = "\n";
+
+ for (size_t i = 0 ; i < str.length() ; i += 16) {
+
+ size_t r = std::min(static_cast <size_t>(16), str.length() - i);
+
+ vmime::string hex;
+ vmime::string chr;
+
+ for (size_t j = 0 ; j < r ; ++j) {
+
+ const unsigned char c = str[i + j];
+
+ hex += hexChars[c / 16];
+ hex += hexChars[c % 16];
+ hex += " ";
+
+ if (c >= 32 && c <= 127)
+ chr += c;
+ else
+ chr += '.';
+ }
+
+ for (size_t j = r ; j < 16 ; ++j) {
+ hex += " ";
+ }
+
+ res += hex + " " + chr + "\n";
+ }
+
+ return res;
+}
diff --git a/vmime-master/tests/testUtils.hpp b/vmime-master/tests/testUtils.hpp
new file mode 100644
index 0000000..e6bf1ee
--- /dev/null
+++ b/vmime-master/tests/testUtils.hpp
@@ -0,0 +1,407 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include <ostream>
+#include <iostream>
+#include <sstream>
+#include <vector>
+#include <string>
+
+
+// VMime
+#include "vmime/vmime.hpp"
+
+
+// CppUnit
+#pragma GCC diagnostic ignored "-Wold-style-cast"
+#include <cppunit/TestAssert.h>
+#include <cppunit/extensions/HelperMacros.h>
+#pragma GCC diagnostic warning "-Wold-style-cast"
+
+#define VASSERT(msg, cond) \
+ CPPUNIT_ASSERT_MESSAGE(std::string(msg), cond)
+
+#define VASSERT_TRUE(msg, cond) \
+ VASSERT(msg, cond)
+#define VASSERT_FALSE(msg, cond) \
+ VASSERT(msg, !(cond))
+
+#define VASSERT_NOT_NULL(msg, cond) \
+ VASSERT(msg, cond != NULL)
+#define VASSERT_NULL(msg, cond) \
+ VASSERT(msg, cond == NULL)
+
+#define VASSERT_EQ(msg, expected, actual) \
+ CPPUNIT_ASSERT_EQUAL_MESSAGE(std::string(msg), expected, actual)
+#define VASSERT_NEQ(msg, expected, actual) \
+ CPPUNIT_ASSERT_MESSAGE(std::string(msg), (expected) != (actual))
+
+#define VASSERT_THROW(msg, expression, exceptionType) \
+ CPPUNIT_ASSERT_THROW(expression, exceptionType)
+#define VASSERT_NO_THROW(msg, expression) \
+ CPPUNIT_ASSERT_NO_THROW(expression)
+
+#define VMIME_TEST_SUITE_BEGIN(testSuiteName) \
+ class testSuiteName; \
+ typedef testSuiteName VMIME_TEST_SUITE; \
+ class testSuiteName : public CppUnit::TestFixture { public:
+#define VMIME_TEST_SUITE_END \
+ }; \
+ \
+ /*static CppUnit::AutoRegisterSuite <VMIME_TEST_SUITE>(autoRegisterRegistry1);*/ \
+ /*static CppUnit::AutoRegisterSuite <VMIME_TEST_SUITE>(autoRegisterRegistry2)(VMIME_TEST_SUITE_MODULE);*/ \
+ extern void registerTestModule(const char* name); \
+ extern const char* getTestModuleNameFromSourceFile(const char *path); \
+ template <typename T> \
+ struct AutoRegisterModule { \
+ AutoRegisterModule() { \
+ static const char* moduleName = getTestModuleNameFromSourceFile(__FILE__); \
+ static CppUnit::AutoRegisterSuite <VMIME_TEST_SUITE>(autoRegisterRegistry1); \
+ static CppUnit::AutoRegisterSuite <VMIME_TEST_SUITE>(autoRegisterRegistry2)(moduleName); \
+ registerTestModule(moduleName); \
+ } \
+ }; \
+ static AutoRegisterModule <VMIME_TEST_SUITE> autoRegisterModule;
+
+#define VMIME_TEST_LIST_BEGIN CPPUNIT_TEST_SUITE(VMIME_TEST_SUITE);
+#define VMIME_TEST_LIST_END CPPUNIT_TEST_SUITE_END(); public:
+#define VMIME_TEST(name) CPPUNIT_TEST(name);
+
+
+namespace CppUnit {
+
+ // Work-around for comparing 'std::string' against 'char*'
+ inline void assertEquals(
+ const char* expected,
+ const std::string actual,
+ SourceLine sourceLine,
+ const std::string &message
+ ) {
+
+ assertEquals(std::string(expected), actual, sourceLine, message);
+ }
+
+ template <typename X, typename Y>
+ void assertEquals(
+ const X expected,
+ const Y actual,
+ SourceLine sourceLine,
+ const std::string &message
+ ) {
+
+ assertEquals(static_cast <Y>(expected), actual, sourceLine, message);
+ }
+}
+
+
+namespace std {
+
+
+inline std::ostream& operator<<(std::ostream& os, const vmime::charset& ch) {
+
+ os << "[charset: " << ch.getName() << "]";
+ return os;
+}
+
+
+inline std::ostream& operator<<(std::ostream& os, const vmime::word& w) {
+
+ os << "[word: charset=" << w.getCharset().getName()
+ << ", buffer=" << w.getBuffer();
+
+ if (!w.getLanguage().empty()) {
+ os << ", lang=" << w.getLanguage();
+ }
+
+ os << "]";
+
+ return os;
+}
+
+
+inline std::ostream& operator<<(std::ostream& os, const vmime::text& txt) {
+
+ os << "[text: [";
+
+ for (size_t i = 0 ; i < txt.getWordCount() ; ++i) {
+
+ const vmime::word& w = *txt.getWordAt(i);
+
+ if (i != 0) {
+ os << ",";
+ }
+
+ os << w;
+ }
+
+ os << "]]";
+
+ return os;
+}
+
+
+inline std::ostream& operator<<(std::ostream& os, const vmime::emailAddress& email) {
+
+ os << email.generate();
+
+ return os;
+}
+
+
+inline std::ostream& operator<<(std::ostream& os, const vmime::mailbox& mbox) {
+
+ os << "[mailbox: name=" << mbox.getName() << ", email=" << mbox.getEmail() << "]";
+
+ return os;
+}
+
+
+inline std::ostream& operator<<(std::ostream& os, const vmime::mailboxGroup& group) {
+
+ os << "[mailbox-group: name=" << group.getName() << ", list=[";
+
+ for (size_t i = 0 ; i < group.getMailboxCount() ; ++i) {
+
+ if (i != 0) {
+ os << ",";
+ }
+
+ os << *group.getMailboxAt(i);
+ }
+
+ os << "]]";
+
+ return os;
+}
+
+
+inline std::ostream& operator<<(std::ostream& os, const vmime::addressList& list) {
+
+ os << "[address-list: [";
+
+ for (size_t i = 0 ; i < list.getAddressCount() ; ++i) {
+
+ const vmime::address& addr = *list.getAddressAt(i);
+
+ if (i != 0) {
+ os << ",";
+ }
+
+ if (addr.isGroup()) {
+
+ const vmime::mailboxGroup& group =
+ dynamic_cast <const vmime::mailboxGroup&>(addr);
+
+ os << group;
+
+ } else {
+
+ const vmime::mailbox& mbox =
+ dynamic_cast <const vmime::mailbox&>(addr);
+
+ os << mbox;
+ }
+ }
+
+ os << "]]";
+
+ return os;
+}
+
+
+inline std::ostream& operator<<(std::ostream& os, const vmime::datetime& d) {
+
+ os << "[datetime: " << d.getYear() << "/" << d.getMonth() << "/" << d.getDay();
+ os << " " << d.getHour() << ":" << d.getMinute() << ":" << d.getSecond();
+ os << " #" << d.getZone() << "]";
+
+ return os;
+}
+
+
+inline std::ostream& operator<<(std::ostream& os, const vmime::encoding& enc) {
+
+ os << enc.generate();
+
+ return os;
+}
+
+
+}
+
+
+
+// Used to test network features.
+//
+// This works like a local pipe: client reads and writes data using receive()
+// and send(). Server reads incoming data with localReceive() and sends data
+// to client with localSend().
+
+class testSocket : public vmime::net::socket {
+
+public:
+
+ void connect(const vmime::string& address, const vmime::port_t port);
+ void disconnect();
+
+ bool isConnected() const;
+
+ bool waitForWrite(const int msecs = 30000);
+ bool waitForRead(const int msecs = 30000);
+
+ void receive(vmime::string& buffer);
+ void send(const vmime::string& buffer);
+ void send(const char* str);
+
+ size_t receiveRaw(vmime::byte_t* buffer, const size_t count);
+ void sendRaw(const vmime::byte_t* buffer, const size_t count);
+ size_t sendRawNonBlocking(const vmime::byte_t* buffer, const size_t count);
+
+ size_t getBlockSize() const;
+
+ unsigned int getStatus() const;
+
+ const vmime::string getPeerName() const;
+ const vmime::string getPeerAddress() const;
+
+ vmime::shared_ptr <vmime::net::timeoutHandler> getTimeoutHandler();
+
+ void setTracer(const vmime::shared_ptr <vmime::net::tracer>& tracer);
+ vmime::shared_ptr <vmime::net::tracer> getTracer();
+
+ /** Send data to client.
+ *
+ * @param buffer data to send
+ */
+ void localSend(const vmime::string& buffer);
+
+ /** Receive data from client.
+ *
+ * @param buffer buffer in which to store received data
+ */
+ void localReceive(vmime::string& buffer);
+
+ /** Receive a line from client.
+ *
+ * @param buffer buffer in which to store received line
+ * @return true if a line has been read, or false otherwise
+ */
+ bool localReceiveLine(vmime::string& buffer);
+
+ /** Receive data from client.
+ *
+ * @param buffer buffer in which to store received data
+ * @param count number of bytes to receive
+ * @return number of bytes received
+ */
+ vmime::size_t localReceiveRaw(vmime::byte_t* buffer, const size_t count);
+
+protected:
+
+ /** Called when the client has sent some data.
+ */
+ virtual void onDataReceived();
+
+ /** Called when the client has connected.
+ */
+ virtual void onConnected();
+
+private:
+
+ vmime::string m_address;
+ vmime::port_t m_port;
+ bool m_connected;
+
+ vmime::string m_inBuffer;
+ vmime::string m_outBuffer;
+};
+
+
+template <typename T>
+class testSocketFactory : public vmime::net::socketFactory {
+
+public:
+
+ vmime::shared_ptr <vmime::net::socket> create() {
+
+ return vmime::make_shared <T>();
+ }
+
+ vmime::shared_ptr <vmime::net::socket> create(
+ const vmime::shared_ptr <vmime::net::timeoutHandler>& /* th */
+ ) {
+
+ return vmime::make_shared <T>();
+ }
+};
+
+
+class lineBasedTestSocket : public testSocket {
+
+public:
+
+ void onDataReceived();
+
+ const vmime::string getNextLine();
+ bool haveMoreLines() const;
+
+ virtual void processCommand() = 0;
+
+private:
+
+ std::vector <vmime::string> m_lines;
+ std::string m_buffer;
+};
+
+
+class testTimeoutHandler : public vmime::net::timeoutHandler {
+
+public:
+
+ testTimeoutHandler(const unsigned long delay = 3);
+
+ bool isTimeOut();
+ void resetTimeOut();
+ bool handleTimeOut();
+
+private:
+
+ unsigned long m_delay;
+ unsigned long m_start;
+};
+
+
+class testTimeoutHandlerFactory : public vmime::net::timeoutHandlerFactory {
+
+public:
+
+ vmime::shared_ptr <vmime::net::timeoutHandler> create();
+};
+
+
+// Exception helper
+std::ostream& operator<<(std::ostream& os, const vmime::exception& e);
+
+
+// Conversion to hexadecimal for easier debugging
+const vmime::string toHex(const vmime::string str);
diff --git a/vmime-master/tests/utility/datetimeUtilsTest.cpp b/vmime-master/tests/utility/datetimeUtilsTest.cpp
new file mode 100644
index 0000000..77ce242
--- /dev/null
+++ b/vmime-master/tests/utility/datetimeUtilsTest.cpp
@@ -0,0 +1,157 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "tests/testUtils.hpp"
+
+#include "vmime/dateTime.hpp"
+#include "vmime/utility/datetimeUtils.hpp"
+
+
+VMIME_TEST_SUITE_BEGIN(datetimeUtilsTest)
+
+ VMIME_TEST_LIST_BEGIN
+ VMIME_TEST(testIsLeapYear)
+ VMIME_TEST(testGetDaysInMonth)
+ VMIME_TEST(testGetDaysInMonthLeapYear)
+ VMIME_TEST(testToUniversalTime)
+ VMIME_TEST(testToLocalTime)
+ VMIME_TEST(testGetDayOfWeek)
+ VMIME_TEST(testGetWeekOfYear)
+ VMIME_TEST_LIST_END
+
+
+ typedef vmime::utility::datetimeUtils datetimeUtils;
+
+
+ void testIsLeapYear() {
+
+ VASSERT_EQ("1", false, datetimeUtils::isLeapYear(1999));
+ VASSERT_EQ("2", false, datetimeUtils::isLeapYear(1800));
+ VASSERT_EQ("3", false, datetimeUtils::isLeapYear(1900));
+ VASSERT_EQ("4", false, datetimeUtils::isLeapYear(2100));
+ VASSERT_EQ("5", false, datetimeUtils::isLeapYear(2200));
+
+ VASSERT_EQ("6", true, datetimeUtils::isLeapYear(1996));
+ VASSERT_EQ("7", true, datetimeUtils::isLeapYear(2000));
+ }
+
+ void testGetDaysInMonth() {
+
+ VASSERT_EQ("1", 31, datetimeUtils::getDaysInMonth(2006, 1));
+ VASSERT_EQ("2", 28, datetimeUtils::getDaysInMonth(2006, 2));
+ VASSERT_EQ("3", 31, datetimeUtils::getDaysInMonth(2006, 3));
+ VASSERT_EQ("4", 30, datetimeUtils::getDaysInMonth(2006, 4));
+ VASSERT_EQ("5", 31, datetimeUtils::getDaysInMonth(2006, 5));
+ VASSERT_EQ("6", 30, datetimeUtils::getDaysInMonth(2006, 6));
+ VASSERT_EQ("7", 31, datetimeUtils::getDaysInMonth(2006, 7));
+ VASSERT_EQ("8", 31, datetimeUtils::getDaysInMonth(2006, 8));
+ VASSERT_EQ("9", 30, datetimeUtils::getDaysInMonth(2006, 9));
+ VASSERT_EQ("10", 31, datetimeUtils::getDaysInMonth(2006, 10));
+ VASSERT_EQ("11", 30, datetimeUtils::getDaysInMonth(2006, 11));
+ VASSERT_EQ("12", 31, datetimeUtils::getDaysInMonth(2006, 12));
+ }
+
+ void testGetDaysInMonthLeapYear() {
+
+ VASSERT_EQ("1", 31, datetimeUtils::getDaysInMonth(2004, 1));
+ VASSERT_EQ("2", 29, datetimeUtils::getDaysInMonth(2004, 2));
+ VASSERT_EQ("3", 31, datetimeUtils::getDaysInMonth(2004, 3));
+ VASSERT_EQ("4", 30, datetimeUtils::getDaysInMonth(2004, 4));
+ VASSERT_EQ("5", 31, datetimeUtils::getDaysInMonth(2004, 5));
+ VASSERT_EQ("6", 30, datetimeUtils::getDaysInMonth(2004, 6));
+ VASSERT_EQ("7", 31, datetimeUtils::getDaysInMonth(2004, 7));
+ VASSERT_EQ("8", 31, datetimeUtils::getDaysInMonth(2004, 8));
+ VASSERT_EQ("9", 30, datetimeUtils::getDaysInMonth(2004, 9));
+ VASSERT_EQ("10", 31, datetimeUtils::getDaysInMonth(2004, 10));
+ VASSERT_EQ("11", 30, datetimeUtils::getDaysInMonth(2004, 11));
+ VASSERT_EQ("12", 31, datetimeUtils::getDaysInMonth(2004, 12));
+ }
+
+ void testToUniversalTime() {
+
+ const vmime::datetime local(2005, 12, 2, 12, 34, 56, -789);
+
+ const vmime::datetime gmt = datetimeUtils::toUniversalTime(local);
+
+ // 789 is 13 hours, 9 minutes later
+ VASSERT_EQ("1", 2005, gmt.getYear());
+ VASSERT_EQ("2", 12, gmt.getMonth());
+ VASSERT_EQ("3", 3, gmt.getDay());
+ VASSERT_EQ("4", 1, gmt.getHour());
+ VASSERT_EQ("5", 43, gmt.getMinute());
+ VASSERT_EQ("6", 56, gmt.getSecond());
+ VASSERT_EQ("7", 0, gmt.getZone());
+ }
+
+ void testToLocalTime() {
+
+ const vmime::datetime date(2005, 12, 2, 12, 34, 56, -120); // GMT-2
+
+ const vmime::datetime local = datetimeUtils::toLocalTime(date, 120); // GMT+2
+
+ VASSERT_EQ("1", 2005, local.getYear());
+ VASSERT_EQ("2", 12, local.getMonth());
+ VASSERT_EQ("3", 2, local.getDay());
+ VASSERT_EQ("4", 16, local.getHour());
+ VASSERT_EQ("5", 34, local.getMinute());
+ VASSERT_EQ("6", 56, local.getSecond());
+ VASSERT_EQ("7", 120, local.getZone());
+ }
+
+ void testGetDayOfWeek() {
+
+ VASSERT_EQ("1", vmime::datetime::WEDNESDAY, datetimeUtils::getDayOfWeek(1969, 12, 31));
+ VASSERT_EQ("2", vmime::datetime::FRIDAY, datetimeUtils::getDayOfWeek(1976, 4, 9));
+ VASSERT_EQ("3", vmime::datetime::TUESDAY, datetimeUtils::getDayOfWeek(1987, 6, 23));
+ VASSERT_EQ("4", vmime::datetime::SATURDAY, datetimeUtils::getDayOfWeek(1990, 1, 13));
+ VASSERT_EQ("5", vmime::datetime::MONDAY, datetimeUtils::getDayOfWeek(1999, 9, 20));
+ VASSERT_EQ("6", vmime::datetime::THURSDAY, datetimeUtils::getDayOfWeek(2003, 2, 27));
+ VASSERT_EQ("7", vmime::datetime::SATURDAY, datetimeUtils::getDayOfWeek(2005, 11, 19));
+ VASSERT_EQ("8", vmime::datetime::WEDNESDAY, datetimeUtils::getDayOfWeek(2012, 5, 16));
+ VASSERT_EQ("9", vmime::datetime::FRIDAY, datetimeUtils::getDayOfWeek(2027, 3, 12));
+ }
+
+ void testGetWeekOfYear() {
+
+ VASSERT_EQ("1.1", 52, datetimeUtils::getWeekOfYear(2003, 12, 27));
+ VASSERT_EQ("1.2", 52, datetimeUtils::getWeekOfYear(2003, 12, 28));
+ VASSERT_EQ("1.3", 1, datetimeUtils::getWeekOfYear(2003, 12, 29, true));
+ VASSERT_EQ("1.4", 53, datetimeUtils::getWeekOfYear(2003, 12, 29, false));
+ VASSERT_EQ("1.5", 1, datetimeUtils::getWeekOfYear(2004, 1, 4));
+ VASSERT_EQ("1.6", 2, datetimeUtils::getWeekOfYear(2004, 1, 5));
+ VASSERT_EQ("1.7", 2, datetimeUtils::getWeekOfYear(2004, 1, 11));
+
+ VASSERT_EQ("2.1", 52, datetimeUtils::getWeekOfYear(2004, 12, 26));
+ VASSERT_EQ("2.2", 53, datetimeUtils::getWeekOfYear(2004, 12, 27));
+ VASSERT_EQ("2.3", 53, datetimeUtils::getWeekOfYear(2005, 1, 2));
+ VASSERT_EQ("2.4", 1, datetimeUtils::getWeekOfYear(2005, 1, 3));
+ VASSERT_EQ("2.5", 1, datetimeUtils::getWeekOfYear(2005, 1, 4));
+ VASSERT_EQ("2.6", 2, datetimeUtils::getWeekOfYear(2005, 1, 11));
+
+ VASSERT_EQ("3.1", 9, datetimeUtils::getWeekOfYear(2027, 3, 7));
+ VASSERT_EQ("3.2", 10, datetimeUtils::getWeekOfYear(2027, 3, 8));
+ VASSERT_EQ("3.3", 10, datetimeUtils::getWeekOfYear(2027, 3, 14));
+ VASSERT_EQ("3.4", 11, datetimeUtils::getWeekOfYear(2027, 3, 15));
+ }
+
+VMIME_TEST_SUITE_END
diff --git a/vmime-master/tests/utility/encoder/b64EncoderTest.cpp b/vmime-master/tests/utility/encoder/b64EncoderTest.cpp
new file mode 100644
index 0000000..36fa61a
--- /dev/null
+++ b/vmime-master/tests/utility/encoder/b64EncoderTest.cpp
@@ -0,0 +1,168 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "tests/testUtils.hpp"
+
+#include "encoderTestUtils.hpp"
+
+
+VMIME_TEST_SUITE_BEGIN(b64EncoderTest)
+
+ VMIME_TEST_LIST_BEGIN
+ VMIME_TEST(testBase64)
+ VMIME_TEST_LIST_END
+
+
+ void testBase64() {
+
+ static const vmime::string testSuites[] = {
+
+ // Test 1
+ "",
+
+ "",
+
+ // Test 2
+ "A",
+
+ "QQ==",
+
+ // Test 3
+ "AB",
+
+ "QUI=",
+
+ // Test 4
+ "ABC",
+
+ "QUJD",
+
+ // Test 5
+ "foo",
+
+ "Zm9v",
+
+ // Test 6
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789",
+
+ "QUJDREVGR0hJSktMTU5PUFFSU1RVVldYWVphYmNkZWZnaGlqa2xtbm9wcXJzdHV2d3h5ejAx"
+ "MjM0NTY3ODk=",
+
+ // Test 7
+ vmime::string(
+ "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
+ "\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f"
+ "\x20\x21\x22\x23\x24\x25\x26\x27\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f"
+ "\x30\x31\x32\x33\x34\x35\x36\x37\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f"
+ "\x40\x41\x42\x43\x44\x45\x46\x47\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f"
+ "\x50\x51\x52\x53\x54\x55\x56\x57\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f"
+ "\x60\x61\x62\x63\x64\x65\x66\x67\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f"
+ "\x70\x71\x72\x73\x74\x75\x76\x77\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f"
+ "\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f"
+ "\x90\x91\x92\x93\x94\x95\x96\x97\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f"
+ "\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xab\xac\xad\xae\xaf"
+ "\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf"
+ "\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf"
+ "\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf"
+ "\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xeb\xec\xed\xee\xef"
+ "\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff",
+ 256),
+
+ "AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8gISIjJCUmJygpKissLS4vMDEyMzQ1"
+ "Njc4OTo7PD0+P0BBQkNERUZHSElKS0xNTk9QUVJTVFVWV1hZWltcXV5fYGFiY2RlZmdoaWpr"
+ "bG1ub3BxcnN0dXZ3eHl6e3x9fn+AgYKDhIWGh4iJiouMjY6PkJGSk5SVlpeYmZqbnJ2en6Ch"
+ "oqOkpaanqKmqq6ytrq+wsbKztLW2t7i5uru8vb6/wMHCw8TFxsfIycrLzM3Oz9DR0tPU1dbX"
+ "2Nna29zd3t/g4eLj5OXm5+jp6uvs7e7v8PHy8/T19vf4+fr7/P3+/w=="
+ };
+
+
+ for (unsigned int i = 0 ; i < sizeof(testSuites) / sizeof(testSuites[0]) / 2 ; ++i) {
+
+ const vmime::string decoded = testSuites[i * 2];
+ const vmime::string encoded = testSuites[i * 2 + 1];
+
+ std::ostringstream oss;
+ oss << "[Base64] Test " << (i + 1) << ": ";
+
+ // Encoding
+ VASSERT_EQ(oss.str() + "encoding", encoded, encode("base64", decoded));
+
+ // Decoding
+ VASSERT_EQ(oss.str() + "decoding", decoded, decode("base64", encoded));
+
+ // Multiple and successive encoding/decoding
+ VASSERT_EQ(
+ oss.str() + "multiple1",
+ decoded,
+ decode("base64",
+ encode("base64", decoded))
+ );
+
+ VASSERT_EQ(
+ oss.str() + "multiple2",
+ decoded,
+ decode("base64",
+ decode("base64",
+ encode("base64",
+ encode("base64", decoded))))
+ );
+
+ VASSERT_EQ(
+ oss.str() + "multiple3",
+ decoded,
+ decode("base64",
+ decode("base64",
+ decode("base64",
+ encode("base64",
+ encode("base64",
+ encode("base64", decoded))))))
+ );
+
+ VASSERT_EQ(
+ oss.str() + "multiple4",
+ decoded,
+ decode("base64",
+ decode("base64",
+ decode("base64",
+ decode("base64",
+ encode("base64",
+ encode("base64",
+ encode("base64",
+ encode("base64", decoded))))))))
+ );
+
+ VASSERT(
+ oss.str() + "encoded size",
+ getEncoder("base64")->getEncodedSize(decoded.length())
+ >= encode("base64", decoded).length()
+ );
+
+ VASSERT(
+ oss.str() + "decoded size",
+ getEncoder("base64")->getDecodedSize(encoded.length())
+ >= decode("base64", encoded).length()
+ );
+ }
+ }
+
+VMIME_TEST_SUITE_END
diff --git a/vmime-master/tests/utility/encoder/encoderFactoryTest.cpp b/vmime-master/tests/utility/encoder/encoderFactoryTest.cpp
new file mode 100644
index 0000000..916706c
--- /dev/null
+++ b/vmime-master/tests/utility/encoder/encoderFactoryTest.cpp
@@ -0,0 +1,63 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "tests/testUtils.hpp"
+
+#include "vmime/utility/encoder/noopEncoder.hpp"
+
+
+
+VMIME_TEST_SUITE_BEGIN(encoderFactoryTest)
+
+ VMIME_TEST_LIST_BEGIN
+ VMIME_TEST(testNoDefaultEncoder)
+ VMIME_TEST(testDefaultEncoder)
+ VMIME_TEST_LIST_END
+
+
+ void testNoDefaultEncoder() {
+
+ vmime::shared_ptr <vmime::utility::encoder::encoderFactory> ef =
+ vmime::utility::encoder::encoderFactory::getInstance();
+
+ VASSERT_THROW(
+ "no default encoder",
+ ef->create("non-existing-encoding"),
+ vmime::exceptions::no_encoder_available
+ );
+ }
+
+ void testDefaultEncoder() {
+
+ vmime::shared_ptr <vmime::utility::encoder::encoderFactory> ef =
+ vmime::utility::encoder::encoderFactory::getInstance();
+
+ ef->setDefaultEncoder(vmime::make_shared <vmime::utility::encoder::noopEncoder>());
+
+ VASSERT_NO_THROW(
+ "default encoder",
+ ef->create("non-existing-encoding")
+ );
+ }
+
+VMIME_TEST_SUITE_END
diff --git a/vmime-master/tests/utility/encoder/encoderTestUtils.hpp b/vmime-master/tests/utility/encoder/encoderTestUtils.hpp
new file mode 100644
index 0000000..cc1141c
--- /dev/null
+++ b/vmime-master/tests/utility/encoder/encoderTestUtils.hpp
@@ -0,0 +1,82 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+
+// Helper function to obtain an encoder given its name
+static vmime::shared_ptr <vmime::utility::encoder::encoder> getEncoder(
+ const vmime::string& name,
+ int maxLineLength = 0,
+ const vmime::propertySet props = vmime::propertySet()
+) {
+
+ vmime::shared_ptr <vmime::utility::encoder::encoder> enc =
+ vmime::utility::encoder::encoderFactory::getInstance()->create(name);
+
+ enc->getProperties() = props;
+
+ if (maxLineLength != 0) {
+ enc->getProperties()["maxlinelength"] = maxLineLength;
+ }
+
+ return enc;
+}
+
+
+// Encoding helper function
+static const vmime::string encode(
+ const vmime::string& name, const vmime::string& in,
+ int maxLineLength = 0,
+ const vmime::propertySet props = vmime::propertySet()
+) {
+
+ vmime::shared_ptr <vmime::utility::encoder::encoder> enc = getEncoder(name, maxLineLength, props);
+
+ vmime::utility::inputStreamStringAdapter vin(in);
+
+ std::ostringstream out;
+ vmime::utility::outputStreamAdapter vout(out);
+
+ enc->encode(vin, vout);
+
+ return (out.str());
+}
+
+
+// Decoding helper function
+static const vmime::string decode(
+ const vmime::string& name,
+ const vmime::string& in,
+ int maxLineLength = 0
+) {
+
+ vmime::shared_ptr <vmime::utility::encoder::encoder> enc = getEncoder(name, maxLineLength);
+
+ vmime::utility::inputStreamStringAdapter vin(in);
+
+ std::ostringstream out;
+ vmime::utility::outputStreamAdapter vout(out);
+
+ enc->decode(vin, vout);
+
+ return (out.str());
+}
diff --git a/vmime-master/tests/utility/encoder/qpEncoderTest.cpp b/vmime-master/tests/utility/encoder/qpEncoderTest.cpp
new file mode 100644
index 0000000..e476947
--- /dev/null
+++ b/vmime-master/tests/utility/encoder/qpEncoderTest.cpp
@@ -0,0 +1,275 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "tests/testUtils.hpp"
+
+#include "encoderTestUtils.hpp"
+
+
+VMIME_TEST_SUITE_BEGIN(qpEncoderTest)
+
+ VMIME_TEST_LIST_BEGIN
+ VMIME_TEST(testQuotedPrintable)
+ VMIME_TEST(testQuotedPrintable_SoftLineBreaks)
+ VMIME_TEST(testQuotedPrintable_HardLineBreakEncode)
+ VMIME_TEST(testQuotedPrintable_HardLineBreakDecode)
+ VMIME_TEST(testQuotedPrintable_CRLF)
+ VMIME_TEST(testQuotedPrintable_RFC2047)
+ VMIME_TEST_LIST_END
+
+
+ void testQuotedPrintable() {
+
+ static const vmime::string testSuites[] = {
+
+ // Test 1
+ "",
+
+ "",
+
+ // Test 2
+ "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ",
+
+ "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ",
+
+ // Test 3
+ "0123456789012345678901234567890123456789012345678901234567890123456789012"
+ "3456789012345678901234567890123456789012345678901234567890123456789012345"
+ "6789",
+
+ "0123456789012345678901234567890123456789012345678901234567890123456789012=\r\n"
+ "3456789012345678901234567890123456789012345678901234567890123456789012345=\r\n"
+ "6789",
+
+ // Test 4
+ vmime::string(
+ "\x89\xe8\x24\x04\x2f\xe8\xff\xfb\xeb\xff\x90\xd7\x74\x8d\x00\x26\x89\x55"
+ "\x83\xe5\x08\xec\x04\xc7\xa0\x24\x05\xa2\xe8\x08\x43\xee\x00\x00\xc0\x85"
+ "\x0a\x74\xec\x89\xc3\x5d\xb6\x8d\x00\x00\x00\x00\x04\xc7\xa8\x24\x05\xa2"
+ "\xe8\x08\x43\xd4\x00\x00\xe8\xeb\xf6\x89\x89\x55\x81\xe5\xa8\xec\x00\x00"
+ "\x89\x00\xfc\x75\x75\x8b\x89\x08\xf8\x5d\xb9\xe8\xff\xff\x83\xff\x14\xfe"
+ "\x47\x74\xc0\x31\x9d\x8d\xff\x68\xff\xff\x85\x89\xff\x68\xff\xff\x85\x8d"
+ "\xff\x6c\xff\xff\x04\x89\xe8\x24\xfa\x50\xff\xff\x45\xc7\x00\xec\x00\x00"
+ "\x31\x00\x89\xc0\x24\x44\x89\x08\x24\x5c\x89\x04\x24\x34\x87\xe8\xff\xf6"
+ "\x89\xff\x24\x34\x2f\xe8\xff\xf9\x8b\xff\xf8\x5d\x75\x8b\x89\xfc\x5d\xec"
+ "\xbe\xc3\x00\x13\x00\x00\xe7\xeb\xb6\x8d\x00\x00\x00\x00\x89\x55\x57\xe5"
+ "\x53\x56\xec\x81\x01\xdc\x00\x00\x45\xbb\x05\x5c\x8b\x08\x0c\x55\xe4\x83"
+ "\x8b\xf0\x89\x02\x24\x5c\xc7\x04\x24\x04\x00\x06\x00\x00\xec\xa3\x05\xa9"
+ "\xe8\x08\xf7\x2a\xff\xff\x04\xc7\x46\x24\x05\x5c\xb9\x08\x5c\x50\x08\x05"
+ "\x4c\x89\x04\x24\xf5\xe8\xff\xf7\xc7\xff\x24\x04\x5c\x46\x08\x05\xe9\xe8"
+ "\xff\xf8\xc7\xff\x24\x04\x1d\x70\x08\x05\x55\xe8\x00\xbb\xb8\x00\x00\x01"
+ "\x00\x00\xd2\x31\x08\xa3\x05\xa7\xb8\x08\x00\x01\x00\x00\x0c\xa3\x05\xa7",
+ 18 * 16),
+
+ "=89=E8$=04/=E8=FF=FB=EB=FF=90=D7t=8D=00&=89U=83=E5=08=EC=04=C7=A0$=05=A2=E8=\r\n"
+ "=08C=EE=00=00=C0=85=0At=EC=89=C3]=B6=8D=00=00=00=00=04=C7=A8$=05=A2=E8=08=\r\n"
+ "C=D4=00=00=E8=EB=F6=89=89U=81=E5=A8=EC=00=00=89=00=FCuu=8B=89=08=F8]=B9=E8=\r\n"
+ "=FF=FF=83=FF=14=FEGt=C01=9D=8D=FFh=FF=FF=85=89=FFh=FF=FF=85=8D=FFl=FF=FF=04=\r\n"
+ "=89=E8$=FAP=FF=FFE=C7=00=EC=00=001=00=89=C0$D=89=08$\\=89=04$4=87=E8=FF=F6=\r\n"
+ "=89=FF$4/=E8=FF=F9=8B=FF=F8]u=8B=89=FC]=EC=BE=C3=00=13=00=00=E7=EB=B6=8D=00=\r\n"
+ "=00=00=00=89UW=E5SV=EC=81=01=DC=00=00E=BB=05\\=8B=08=0CU=E4=83=8B=F0=89=02=\r\n"
+ "$\\=C7=04$=04=00=06=00=00=EC=A3=05=A9=E8=08=F7*=FF=FF=04=C7F$=05\\=B9=08\\P=08=\r\n"
+ "=05L=89=04$=F5=E8=FF=F7=C7=FF$=04\\F=08=05=E9=E8=FF=F8=C7=FF$=04=1Dp=08=05=\r\n"
+ "U=E8=00=BB=B8=00=00=01=00=00=D21=08=A3=05=A7=B8=08=00=01=00=00=0C=A3=05=A7=\r\n"
+ };
+
+
+ for (unsigned int i = 0 ; i < sizeof(testSuites) / sizeof(testSuites[0]) / 2 ; ++i) {
+
+ const vmime::string decoded = testSuites[i * 2];
+ const vmime::string encoded = testSuites[i * 2 + 1];
+
+ std::ostringstream oss;
+ oss << "[QP] Test " << (i + 1) << ": ";
+
+ // Encoding
+ VASSERT_EQ(oss.str() + "encoding", encoded, encode("quoted-printable", decoded, 74));
+
+ // Decoding
+ VASSERT_EQ(oss.str() + "decoding", decoded, decode("quoted-printable", encoded, 74));
+
+ // Multiple and successive encoding/decoding
+ VASSERT_EQ(
+ oss.str() + "multiple1",
+ decoded,
+ decode("quoted-printable",
+ encode("quoted-printable", decoded))
+ );
+
+ VASSERT_EQ(
+ oss.str() + "multiple2",
+ decoded,
+ decode("quoted-printable",
+ decode("quoted-printable",
+ encode("quoted-printable",
+ encode("quoted-printable", decoded))))
+ );
+
+ VASSERT_EQ(
+ oss.str() + "multiple3",
+ decoded,
+ decode("quoted-printable",
+ decode("quoted-printable",
+ decode("quoted-printable",
+ encode("quoted-printable",
+ encode("quoted-printable",
+ encode("quoted-printable", decoded))))))
+ );
+
+ VASSERT_EQ(
+ oss.str() + "multiple4",
+ decoded,
+ decode("quoted-printable",
+ decode("quoted-printable",
+ decode("quoted-printable",
+ decode("quoted-printable",
+ encode("quoted-printable",
+ encode("quoted-printable",
+ encode("quoted-printable",
+ encode("quoted-printable", decoded))))))))
+ );
+
+ VASSERT(
+ oss.str() + "encoded size",
+ getEncoder("quoted-printable")->getEncodedSize(decoded.length())
+ >= encode("quoted-printable", decoded).length()
+ );
+
+ VASSERT(
+ oss.str() + "decoded size",
+ getEncoder("quoted-printable")->getDecodedSize(encoded.length())
+ >= decode("quoted-printable", encoded).length()
+ );
+ }
+ }
+
+ /** Tests Soft Line Breaks (RFC-2047/6.7(5). */
+ void testQuotedPrintable_SoftLineBreaks() {
+
+ VASSERT_EQ(
+ "1",
+ "Now's the time=\r\n"
+ " for all folk =\r\n"
+ "to come to the=\r\n"
+ " aid of their =\r\n"
+ "country.",
+ encode(
+ "quoted-printable",
+ "Now's the time for all folk "
+ "to come to the aid of their country.",
+ 15
+ )
+ );
+ }
+
+ void testQuotedPrintable_HardLineBreakEncode() {
+
+ const std::string data =
+ "If you believe that truth=beauty,"
+ " then surely mathematics\r\nis the most"
+ " beautiful branch of philosophy.";
+
+ const std::string expected =
+ "If you believe that truth=3Dbeauty=\r\n"
+ ", then surely mathematics\r\n"
+ "is the most beautiful branch of ph=\r\n"
+ "ilosophy.";
+
+ vmime::propertySet encProps;
+ encProps["text"] = true;
+
+ VASSERT_EQ("1", expected, encode("quoted-printable", data, 35, encProps));
+ }
+
+ void testQuotedPrintable_HardLineBreakDecode() {
+
+ const std::string expected =
+ "If you believe that truth=beauty,"
+ " then surely mathematics\r\nis the most"
+ " beautiful branch of philosophy.";
+
+ const std::string data =
+ "If you believe that truth=3Dbeauty=\r\n"
+ ", then surely mathematics\r\n"
+ "is the most beautiful branch of ph=\r\n"
+ "ilosophy.";
+
+ VASSERT_EQ("1", expected, decode("quoted-printable", data, 35));
+ }
+
+
+ /** In text mode, ensure line breaks in QP-encoded text are represented
+ * by a CRLF sequence, as per RFC-2047/6.7(4). */
+ void testQuotedPrintable_CRLF() {
+
+ vmime::propertySet encProps;
+
+ // in "text" mode
+ encProps["text"] = true;
+ VASSERT_EQ(
+ "text",
+ "line1\r\nline2",
+ encode("quoted-printable", "line1\r\nline2", 80, encProps)
+ );
+
+ // in "binary" mode
+ encProps["text"] = false;
+ VASSERT_EQ(
+ "binary",
+ "line1=0D=0Aline2",
+ encode("quoted-printable", "line1\r\nline2", 80, encProps)
+ );
+ }
+
+ void testQuotedPrintable_RFC2047() {
+
+ /*
+ * The RFC (http://tools.ietf.org/html/rfc2047#section-5) says:
+ *
+ * In this case the set of characters that may be used in a "Q"-encoded
+ * 'encoded-word' is restricted to: <upper and lower case ASCII
+ * letters, decimal digits, "!", "*", "+", "-", "/", "=", and "_"
+ * (underscore, ASCII 95.)>. An 'encoded-word' that appears within a
+ * 'phrase' MUST be separated from any adjacent 'word', 'text' or
+ * 'special' by 'linear-white-space'.
+ */
+
+ vmime::propertySet encProps;
+ encProps["rfc2047"] = true;
+
+ // Ensure 'especials' are encoded
+ VASSERT_EQ("especials.1", "=2C", encode("quoted-printable", ",", 10, encProps));
+ VASSERT_EQ("especials.2", "=3B", encode("quoted-printable", ";", 10, encProps));
+ VASSERT_EQ("especials.3", "=3A", encode("quoted-printable", ":", 10, encProps));
+ VASSERT_EQ("especials.4", "=5F", encode("quoted-printable", "_", 10, encProps));
+ VASSERT_EQ("especials.5", "=40", encode("quoted-printable", "@", 10, encProps));
+ VASSERT_EQ("especials.6", "=28", encode("quoted-printable", "(", 10, encProps));
+ VASSERT_EQ("especials.7", "=29", encode("quoted-printable", ")", 10, encProps));
+ VASSERT_EQ("especials.8", "=3C", encode("quoted-printable", "<", 10, encProps));
+ VASSERT_EQ("especials.9", "=3E", encode("quoted-printable", ">", 10, encProps));
+ VASSERT_EQ("especials.10", "=5B", encode("quoted-printable", "[", 10, encProps));
+ VASSERT_EQ("especials.11", "=5D", encode("quoted-printable", "]", 10, encProps));
+ VASSERT_EQ("especials.12", "=22", encode("quoted-printable", "\"", 10, encProps));
+ }
+
+VMIME_TEST_SUITE_END
diff --git a/vmime-master/tests/utility/filteredStreamTest.cpp b/vmime-master/tests/utility/filteredStreamTest.cpp
new file mode 100644
index 0000000..ff3fb6a
--- /dev/null
+++ b/vmime-master/tests/utility/filteredStreamTest.cpp
@@ -0,0 +1,341 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "tests/testUtils.hpp"
+
+#include "vmime/utility/filteredStream.hpp"
+#include "vmime/utility/stringUtils.hpp"
+
+
+VMIME_TEST_SUITE_BEGIN(filteredStreamTest)
+
+ VMIME_TEST_LIST_BEGIN
+ VMIME_TEST(testDotFilteredInputStream)
+ VMIME_TEST(testDotFilteredOutputStream)
+ VMIME_TEST(testCRLFToLFFilteredOutputStream)
+ VMIME_TEST(testStopSequenceFilteredInputStream1)
+ VMIME_TEST(testStopSequenceFilteredInputStreamN_2)
+ VMIME_TEST(testStopSequenceFilteredInputStreamN_3)
+ VMIME_TEST(testLFToCRLFFilteredOutputStream_Global)
+ VMIME_TEST(testLFToCRLFFilteredOutputStream_Edge)
+ VMIME_TEST_LIST_END
+
+
+ class chunkInputStream : public vmime::utility::inputStream {
+
+ private:
+
+ std::vector <std::string> m_chunks;
+ size_t m_index;
+
+ public:
+
+ chunkInputStream() : m_index(0) { }
+
+ void addChunk(const std::string& chunk) { m_chunks.push_back(chunk); }
+
+ bool eof() const { return (m_index >= m_chunks.size()); }
+ void reset() { m_index = 0; }
+
+ vmime::size_t read(vmime::byte_t* const data, const vmime::size_t /* count */) {
+
+ if (eof()) {
+ return 0;
+ }
+
+ const std::string chunk = m_chunks[m_index];
+
+ // Warning: 'count' should be larger than chunk length.
+ // This is OK for our tests.
+ std::copy(chunk.begin(), chunk.end(), data);
+
+ ++m_index;
+
+ return chunk.length();
+ }
+
+ vmime::size_t skip(const vmime::size_t /* count */) {
+
+ // Not supported
+ return 0;
+ }
+ };
+
+
+ const std::string readWhole(vmime::utility::inputStream& is) {
+
+ vmime::byte_t buffer[256];
+ std::string whole;
+
+ while (!is.eof()) {
+
+ const vmime::size_t read = is.read(buffer, sizeof(buffer));
+
+ whole += vmime::utility::stringUtils::makeStringFromBytes(buffer, read);
+ }
+
+ return whole;
+ }
+
+
+ // dotFilteredInputStream
+
+ void testDotFilteredInputStreamHelper(
+ const std::string& number,
+ const std::string& expected,
+ const std::string& c1,
+ const std::string& c2 = "",
+ const std::string& c3 = "",
+ const std::string& c4 = ""
+ ) {
+
+ chunkInputStream cis;
+ cis.addChunk(c1);
+ if (!c2.empty()) cis.addChunk(c2);
+ if (!c3.empty()) cis.addChunk(c3);
+ if (!c4.empty()) cis.addChunk(c4);
+
+ vmime::utility::dotFilteredInputStream is(cis);
+
+ std::ostringstream oss;
+ vmime::utility::outputStreamAdapter os(oss);
+
+ vmime::utility::bufferedStreamCopy(is, os);
+
+ VASSERT_EQ(number, expected, oss.str());
+ }
+
+ void testDotFilteredInputStream() {
+
+ testDotFilteredInputStreamHelper("1", "foo\n.bar", "foo\n..bar");
+ testDotFilteredInputStreamHelper("2", "foo\n.bar", "foo\n", "..bar");
+ testDotFilteredInputStreamHelper("3", "foo\n.bar", "foo\n.", ".bar");
+ testDotFilteredInputStreamHelper("4", "foo\n.bar", "foo\n..", "bar");
+ testDotFilteredInputStreamHelper("5", "foo\n.bar", "foo\n", ".", ".bar");
+ testDotFilteredInputStreamHelper("6", "foo\n.bar", "foo\n", ".", ".", "bar");
+
+ testDotFilteredInputStreamHelper("7", "\x0d\x0a.", "\x0d\x0a..");
+ testDotFilteredInputStreamHelper("8", "\x0d\x0a.\x0d\x0a", "\x0d\x0a..\x0d\x0a");
+ testDotFilteredInputStreamHelper("9", "\x0d\x0a.\x0d\x0a.", "\x0d\x0a..\x0d\x0a.");
+ testDotFilteredInputStreamHelper("10", "\x0d\x0a.\x0d\x0a.\x0d\x0ax", "\x0d\x0a..\x0d\x0a.\x0d\x0ax");
+ testDotFilteredInputStreamHelper("11", "this is the first line\x0d\x0a.\x0d\x0aone dot\x0d\x0a..\x0d\x0atwo dots\x0d\x0a...\x0d\x0athree... \x0d\x0a.\x0d\x0a.\x0d\x0a", "this is the first line\x0d\x0a..\x0d\x0aone dot\x0d\x0a...\x0d\x0atwo dots\x0d\x0a....\x0d\x0athree... \x0d\x0a..\x0d\x0a.\x0d\x0a");
+ }
+
+ // dotFilteredOutputStream
+ // CRLFToLFFilteredOutputStream
+
+ template <typename FILTER>
+ void testFilteredOutputStreamHelper(
+ const std::string& number,
+ const std::string& expected,
+ const std::string& c1,
+ const std::string& c2 = "",
+ const std::string& c3 = "",
+ const std::string& c4 = ""
+ ) {
+
+ std::ostringstream oss;
+ vmime::utility::outputStreamAdapter os(oss);
+
+ FILTER fos(os);
+
+ fos.write(c1.data(), c1.length());
+ if (!c2.empty()) fos.write(c2.data(), c2.length());
+ if (!c3.empty()) fos.write(c3.data(), c3.length());
+ if (!c4.empty()) fos.write(c4.data(), c4.length());
+
+ VASSERT_EQ(number, expected, oss.str());
+ }
+
+ void testDotFilteredOutputStream() {
+
+ typedef vmime::utility::dotFilteredOutputStream FILTER;
+
+ testFilteredOutputStreamHelper<FILTER>("1", "foo\n..bar", "foo\n.bar");
+ testFilteredOutputStreamHelper<FILTER>("2", "foo\n..bar", "foo\n", ".bar");
+ testFilteredOutputStreamHelper<FILTER>("3", "foo\n..bar", "foo", "\n.bar");
+ testFilteredOutputStreamHelper<FILTER>("4", "foo\n..bar", "foo", "\n", ".bar");
+ testFilteredOutputStreamHelper<FILTER>("5", "foo\n..bar", "foo", "\n", ".", "bar");
+
+ testFilteredOutputStreamHelper<FILTER>("6", "..\nfoobar", ".\nfoobar");
+ testFilteredOutputStreamHelper<FILTER>("7", "..\r\nfoobar", ".\r\nfoobar");
+ testFilteredOutputStreamHelper<FILTER>("8", "..\r\nfoobar", ".\r", "\nfoobar");
+ testFilteredOutputStreamHelper<FILTER>("9", ".foobar", ".foobar");
+ testFilteredOutputStreamHelper<FILTER>("10", ".foobar", ".", "foobar");
+
+ testFilteredOutputStreamHelper<FILTER>("11", "this is the first line\x0d\x0a...\x0d\x0aone dot\x0d\x0a....\x0d\x0atwo dots\x0d\x0a.....\x0d\x0athree... \x0d\x0a...\x0d\x0a..\x0d\x0a", "this is the first line\x0d\x0a..\x0d\x0aone dot\x0d\x0a...\x0d\x0atwo dots\x0d\x0a....\x0d\x0athree... \x0d\x0a..\x0d\x0a.\x0d\x0a");
+ }
+
+ void testCRLFToLFFilteredOutputStream() {
+
+ typedef vmime::utility::CRLFToLFFilteredOutputStream FILTER;
+
+ testFilteredOutputStreamHelper<FILTER>("1", "foo\nbar", "foo\r\nbar");
+ testFilteredOutputStreamHelper<FILTER>("2", "foo\nbar", "foo\r\n", "bar");
+ testFilteredOutputStreamHelper<FILTER>("3", "foo\nbar", "foo\r", "\nbar");
+ testFilteredOutputStreamHelper<FILTER>("4", "foo\nbar", "foo", "\r\nbar");
+ testFilteredOutputStreamHelper<FILTER>("5", "foo\nbar", "foo", "\r", "\nbar");
+ testFilteredOutputStreamHelper<FILTER>("6", "foo\nbar", "foo", "\r", "\n", "bar");
+ testFilteredOutputStreamHelper<FILTER>("7", "foo\nba\nr", "foo\r", "\nba\r\nr");
+ }
+
+ // stopSequenceFilteredInputStream
+
+ template <int N>
+ void testStopSequenceFISHelper(
+ const std::string& number,
+ const std::string& sequence,
+ const std::string& expected,
+ const std::string& c1,
+ const std::string& c2 = "",
+ const std::string& c3 = "",
+ const std::string& c4 = "",
+ const std::string& c5 = ""
+ ) {
+
+ chunkInputStream cis;
+ cis.addChunk(c1);
+ if (!c2.empty()) cis.addChunk(c2);
+ if (!c3.empty()) cis.addChunk(c3);
+ if (!c4.empty()) cis.addChunk(c4);
+ if (!c5.empty()) cis.addChunk(c5);
+
+ vmime::utility::stopSequenceFilteredInputStream <N> is(cis, sequence.data());
+
+ VASSERT_EQ(number, expected, readWhole(is));
+ }
+
+ void testStopSequenceFilteredInputStream1() {
+
+ testStopSequenceFISHelper <1>("1", "x", "foo", "fooxbar");
+ testStopSequenceFISHelper <1>("2", "x", "foo", "foox", "bar");
+ testStopSequenceFISHelper <1>("3", "x", "foo", "foo", "x", "bar");
+ testStopSequenceFISHelper <1>("4", "x", "foo", "fo", "o", "x", "bar");
+ testStopSequenceFISHelper <1>("5", "x", "foo", "fo", "o", "x", "b", "ar");
+
+ testStopSequenceFISHelper <1>("6", "x", "foobar", "fo", "o", "b", "ar");
+ testStopSequenceFISHelper <1>("7", "x", "foobar", "foo", "bar");
+ testStopSequenceFISHelper <1>("8", "x", "foobar", "foo", "b", "ar");
+
+ testStopSequenceFISHelper <1>("9", "x", "foobar", "foobar");
+ testStopSequenceFISHelper <1>("10", "x", "foobar", "foobarx");
+
+ testStopSequenceFISHelper <1>("11", "x", "", "");
+ testStopSequenceFISHelper <1>("12", "x", "", "x");
+ testStopSequenceFISHelper <1>("13", "x", "", "", "x");
+ }
+
+ void testStopSequenceFilteredInputStreamN_2() {
+
+ testStopSequenceFISHelper <2>("1", "xy", "foo", "fooxybar");
+ testStopSequenceFISHelper <2>("2", "xy", "foo", "foox", "ybar");
+ testStopSequenceFISHelper <2>("3", "xy", "foo", "foox", "y", "bar");
+ testStopSequenceFISHelper <2>("4", "xy", "foo", "foo", "x", "ybar");
+ testStopSequenceFISHelper <2>("5", "xy", "foo", "foo", "xy", "bar");
+ testStopSequenceFISHelper <2>("6", "xy", "foo", "foo", "x", "y", "bar");
+
+ testStopSequenceFISHelper <2>("7", "xy", "fooxbar", "foox", "bar");
+ testStopSequenceFISHelper <2>("8", "xy", "fooxbar", "foo", "xbar");
+ testStopSequenceFISHelper <2>("9", "xy", "fooxbar", "foo", "x", "bar");
+ testStopSequenceFISHelper <2>("10", "xy", "foobarx", "foo", "barx");
+
+ testStopSequenceFISHelper <2>("11", "xy", "foobar", "foobarxy");
+ testStopSequenceFISHelper <2>("12", "xy", "foobar", "foo", "barxy");
+ testStopSequenceFISHelper <2>("13", "xy", "foobar", "foo", "bar", "xy");
+
+ testStopSequenceFISHelper <2>("14", "xy", "", "");
+ testStopSequenceFISHelper <2>("15", "xy", "x", "x");
+ testStopSequenceFISHelper <2>("16", "xy", "", "xy");
+ testStopSequenceFISHelper <2>("17", "xy", "", "x", "y");
+ }
+
+ void testStopSequenceFilteredInputStreamN_3() {
+
+ testStopSequenceFISHelper <3>("1", "xyz", "foo", "fooxyzbar");
+ testStopSequenceFISHelper <3>("2", "xyz", "foo", "foox", "yzbar");
+ testStopSequenceFISHelper <3>("3", "xyz", "foo", "foox", "y", "zbar");
+ testStopSequenceFISHelper <3>("4", "xyz", "foo", "foox", "yz", "bar");
+ testStopSequenceFISHelper <3>("5", "xyz", "foo", "foo", "xyz", "bar");
+ testStopSequenceFISHelper <3>("6", "xyz", "foo", "foo", "xy", "zbar");
+ testStopSequenceFISHelper <3>("7", "xyz", "foo", "foo", "x", "y", "zbar");
+ testStopSequenceFISHelper <3>("8", "xyz", "foo", "foo", "x", "y", "z", "bar");
+ testStopSequenceFISHelper <3>("9", "xyz", "foo", "fooxy", "z", "bar");
+
+ testStopSequenceFISHelper <3>("10", "xyz", "fooxybar", "foox", "y", "bar");
+ testStopSequenceFISHelper <3>("11", "xyz", "fooxybar", "fooxy", "bar");
+ testStopSequenceFISHelper <3>("12", "xyz", "fooxybar", "fo", "ox", "y", "bar");
+ testStopSequenceFISHelper <3>("13", "xyz", "fooxybar", "fo", "o", "x", "y", "bar");
+ testStopSequenceFISHelper <3>("14", "xyz", "fooxybar", "foo", "x", "ybar");
+ testStopSequenceFISHelper <3>("15", "xyz", "fooxybar", "foo", "xybar");
+
+ testStopSequenceFISHelper <3>("16", "xyz", "xfoxoxybxar", "xfoxo", "xybxar");
+ testStopSequenceFISHelper <3>("17", "xyz", "xfoxoxybxarx", "xfoxo", "xybxarx");
+ testStopSequenceFISHelper <3>("18", "xyz", "xfoxoxybxarxy", "xfoxo", "xybxarxy");
+
+ testStopSequenceFISHelper <3>("19", "xyz", "", "");
+ testStopSequenceFISHelper <3>("20", "xyz", "x", "x");
+ testStopSequenceFISHelper <3>("21", "xyz", "xy", "xy");
+ testStopSequenceFISHelper <3>("22", "xyz", "", "xyz");
+ testStopSequenceFISHelper <3>("23", "xyz", "", "x", "yz");
+ testStopSequenceFISHelper <3>("24", "xyz", "", "x", "y", "z");
+ }
+
+
+ // LFToCRLFFilteredOutputStream
+
+ void testLFToCRLFFilteredOutputStream_Global() {
+
+ typedef vmime::utility::LFToCRLFFilteredOutputStream FILTER;
+
+ testFilteredOutputStreamHelper<FILTER>("1", "ABC\r\nDEF", "ABC\nDEF");
+ testFilteredOutputStreamHelper<FILTER>("2", "ABC\r\nDEF", "ABC\rDEF");
+ testFilteredOutputStreamHelper<FILTER>("3", "\r\n\r\nAB\r\n\r\nA\r\nB\r\n", "\n\nAB\n\nA\nB\n");
+ testFilteredOutputStreamHelper<FILTER>("4", "ABCDE\r\nF", "ABCDE\nF");
+ testFilteredOutputStreamHelper<FILTER>("5", "ABCDE\r\nF", "ABCDE\r\nF");
+ testFilteredOutputStreamHelper<FILTER>("6", "\r\n\r\n\r\n", "\n\n\n");
+ testFilteredOutputStreamHelper<FILTER>("7", "\r\n\r\n\r\n", "\r\r\n\n");
+ testFilteredOutputStreamHelper<FILTER>("8", "\r\n\r\n\r\n\r\n", "\r\r\r\r");
+ testFilteredOutputStreamHelper<FILTER>("9", "\r\n\r\n\r\n\r\n", "\n\n\n\n");
+ testFilteredOutputStreamHelper<FILTER>("10", "\r\n\r\n\r\n", "\r\n\n\n");
+ testFilteredOutputStreamHelper<FILTER>("11", "\r\n\r\n\r\n\r\n", "\n\n\n\r\n");
+ }
+
+ void testLFToCRLFFilteredOutputStream_Edge() {
+
+ typedef vmime::utility::LFToCRLFFilteredOutputStream FILTER;
+
+ testFilteredOutputStreamHelper<FILTER>("1", "\r\n\r\n", "\r", "\r");
+ testFilteredOutputStreamHelper<FILTER>("2", "\r\n\r\n", "\r", "\n\r");
+ testFilteredOutputStreamHelper<FILTER>("3", "ABC\r\n\r\n", "ABC\r", "\n\r");
+ testFilteredOutputStreamHelper<FILTER>("4", "ABC\r\n\r\n\r\n", "ABC\r", "\n\r", "\n\n");
+ testFilteredOutputStreamHelper<FILTER>("5", "\r\n\r\n", "\n", "\n");
+ testFilteredOutputStreamHelper<FILTER>("6", "\r\n\r\n", "\r\n\r\n");
+ testFilteredOutputStreamHelper<FILTER>("7", "\r\n\r\n", "\r\n\r", "\n");
+
+ testFilteredOutputStreamHelper<FILTER>("8", "A\r\nB\r\nC\r\nD", "A\rB", "\nC\r\nD");
+ testFilteredOutputStreamHelper<FILTER>("9", "\r\nA\r\nB\r\nC\r\nD", "\rA\r", "B\nC\r\nD");
+ testFilteredOutputStreamHelper<FILTER>("10", "\r\nA\r\nB\r\nC\r\nD", "\nA\r", "B\nC\r\nD");
+ testFilteredOutputStreamHelper<FILTER>("11", "\r\nA\r\nB\r\nC\r\nD\r\n", "\nA\rB", "\nC\r\nD\r");
+ }
+
+VMIME_TEST_SUITE_END
diff --git a/vmime-master/tests/utility/outputStreamByteArrayAdapterTest.cpp b/vmime-master/tests/utility/outputStreamByteArrayAdapterTest.cpp
new file mode 100644
index 0000000..07a0f4b
--- /dev/null
+++ b/vmime-master/tests/utility/outputStreamByteArrayAdapterTest.cpp
@@ -0,0 +1,82 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "tests/testUtils.hpp"
+
+#include "vmime/utility/outputStreamByteArrayAdapter.hpp"
+
+
+VMIME_TEST_SUITE_BEGIN(outputStreamByteArrayAdapterTest)
+
+ VMIME_TEST_LIST_BEGIN
+ VMIME_TEST(testWrite)
+ VMIME_TEST(testWriteBinary)
+ VMIME_TEST(testWriteCRLF)
+ VMIME_TEST_LIST_END
+
+
+ void testWrite() {
+
+ vmime::byteArray bytes;
+
+ vmime::utility::outputStreamByteArrayAdapter stream(bytes);
+ stream << "some data";
+ stream.flush();
+
+ VASSERT_EQ("Write 1", 0, memcmp("some data", &bytes[0], 9));
+
+ stream.write("more data", 9);
+
+ VASSERT_EQ("Write 2", 0, memcmp("some datamore data", &bytes[0], 18));
+ }
+
+ void testWriteBinary() {
+
+ const char binaryData[] =
+ "\xc5\x9a\xc3\xb8\xc9\xb1\xc9\x9b\x20\xc9\x93\xc9\xa8\xc9\xb2\xc9"
+ "\x91\xc5\x95\xc9\xa3\x20\xc9\x96\xc9\x90\xca\x88\xc9\x92";
+
+ vmime::byteArray bytes;
+
+ vmime::utility::outputStreamByteArrayAdapter stream(bytes);
+ stream.write(binaryData, sizeof(binaryData));
+ stream.flush();
+
+ VASSERT_EQ("Write", 0, memcmp(binaryData, &bytes[0], sizeof(binaryData)));
+ }
+
+ void testWriteCRLF() {
+
+ vmime::byteArray bytes;
+
+ vmime::utility::outputStreamByteArrayAdapter stream(bytes);
+ stream << "some data";
+ stream.flush();
+
+ stream << "\nmore\r\ndata\r";
+ stream.flush();
+
+ VASSERT_EQ("Write", 0, memcmp("some data\nmore\r\ndata\r", &bytes[0], 21));
+ }
+
+VMIME_TEST_SUITE_END
diff --git a/vmime-master/tests/utility/outputStreamSocketAdapterTest.cpp b/vmime-master/tests/utility/outputStreamSocketAdapterTest.cpp
new file mode 100644
index 0000000..a869ed7
--- /dev/null
+++ b/vmime-master/tests/utility/outputStreamSocketAdapterTest.cpp
@@ -0,0 +1,87 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "tests/testUtils.hpp"
+
+#include "vmime/utility/outputStreamSocketAdapter.hpp"
+
+
+VMIME_TEST_SUITE_BEGIN(outputStreamSocketAdapterTest)
+
+ VMIME_TEST_LIST_BEGIN
+ VMIME_TEST(testWrite)
+ VMIME_TEST(testWriteBinary)
+ VMIME_TEST(testWriteCRLF)
+ VMIME_TEST_LIST_END
+
+
+ void testWrite() {
+
+ vmime::shared_ptr <testSocket> socket = vmime::make_shared <testSocket>();
+
+ vmime::utility::outputStreamSocketAdapter stream(*socket);
+ stream << "some data";
+ stream.flush();
+
+ vmime::string buffer;
+ socket->localReceive(buffer);
+
+ VASSERT_EQ("Write", "some data", buffer);
+ }
+
+ void testWriteBinary() {
+
+ const char binaryData[] =
+ "\xc5\x9a\xc3\xb8\xc9\xb1\xc9\x9b\x20\xc9\x93\xc9\xa8\xc9\xb2\xc9"
+ "\x91\xc5\x95\xc9\xa3\x20\xc9\x96\xc9\x90\xca\x88\xc9\x92";
+
+ vmime::shared_ptr <testSocket> socket = vmime::make_shared <testSocket>();
+
+ vmime::utility::outputStreamSocketAdapter stream(*socket);
+ stream.write(binaryData, sizeof(binaryData));
+ stream.flush();
+
+ vmime::string buffer;
+ socket->localReceive(buffer);
+
+ VASSERT_EQ("Write", 0, memcmp(binaryData, buffer.data(), sizeof(binaryData)));
+ }
+
+ void testWriteCRLF() {
+
+ vmime::shared_ptr <testSocket> socket = vmime::make_shared <testSocket>();
+
+ vmime::utility::outputStreamSocketAdapter stream(*socket);
+ stream << "some data";
+ stream.flush();
+
+ stream << "\nmore\r\ndata\r";
+ stream.flush();
+
+ vmime::string buffer;
+ socket->localReceive(buffer);
+
+ VASSERT_EQ("Write", "some data\nmore\r\ndata\r", buffer);
+ }
+
+VMIME_TEST_SUITE_END
diff --git a/vmime-master/tests/utility/outputStreamStringAdapterTest.cpp b/vmime-master/tests/utility/outputStreamStringAdapterTest.cpp
new file mode 100644
index 0000000..3de8f8b
--- /dev/null
+++ b/vmime-master/tests/utility/outputStreamStringAdapterTest.cpp
@@ -0,0 +1,84 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "tests/testUtils.hpp"
+
+#include "vmime/utility/outputStreamStringAdapter.hpp"
+
+
+VMIME_TEST_SUITE_BEGIN(outputStreamStringAdapterTest)
+
+ VMIME_TEST_LIST_BEGIN
+ VMIME_TEST(testWrite)
+ VMIME_TEST(testWriteBinary)
+ VMIME_TEST(testWriteCRLF)
+ VMIME_TEST_LIST_END
+
+
+ void testWrite() {
+
+ vmime::string str("initial data");
+
+ vmime::utility::outputStreamStringAdapter stream(str);
+ stream << "additional data";
+ stream.flush();
+
+ VASSERT_EQ("Write 1 len", 27, str.length());
+ VASSERT_EQ("Write 1 data", "initial dataadditional data", str);
+
+ stream.write("more data");
+
+ VASSERT_EQ("Write 2 len", 36, str.length());
+ VASSERT_EQ("Write 2 data", "initial dataadditional datamore data", str);
+ }
+
+ void testWriteBinary() {
+
+ const vmime::byte_t binaryData[] =
+ "\xc5\x9a\xc3\xb8\xc9\xb1\xc9\x9b\x20\xc9\x93\xc9\xa8\xc9\xb2\xc9"
+ "\x91\xc5\x95\xc9\xa3\x20\xc9\x96\xc9\x90\xca\x88\xc9\x92";
+
+ vmime::string str;
+
+ vmime::utility::outputStreamStringAdapter stream(str);
+ stream.write(binaryData, sizeof(binaryData));
+ stream.flush();
+
+ VASSERT_EQ("Write", 0, memcmp(binaryData, str.data(), sizeof(binaryData)));
+ }
+
+ void testWriteCRLF() {
+
+ vmime::string str;
+
+ vmime::utility::outputStreamStringAdapter stream(str);
+ stream << "some data";
+ stream.flush();
+
+ stream << "\nmore\r\ndata\r";
+ stream.flush();
+
+ VASSERT_EQ("Write", "some data\nmore\r\ndata\r", str);
+ }
+
+VMIME_TEST_SUITE_END
diff --git a/vmime-master/tests/utility/parserInputStreamAdapterTest.cpp b/vmime-master/tests/utility/parserInputStreamAdapterTest.cpp
new file mode 100644
index 0000000..4bc310c
--- /dev/null
+++ b/vmime-master/tests/utility/parserInputStreamAdapterTest.cpp
@@ -0,0 +1,51 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "tests/testUtils.hpp"
+
+#include "vmime/utility/parserInputStreamAdapter.hpp"
+
+
+VMIME_TEST_SUITE_BEGIN(parserInputStreamAdapterTest)
+
+ VMIME_TEST_LIST_BEGIN
+ VMIME_TEST(testEndlessLoopBufferSize)
+ VMIME_TEST_LIST_END
+
+
+ void testEndlessLoopBufferSize() {
+
+ static const unsigned int BUFFER_SIZE = 4096; // same as in parserInputStreamAdapter::findNext()
+
+ vmime::string str(BUFFER_SIZE, 'X');
+
+ vmime::shared_ptr <vmime::utility::inputStreamStringAdapter> iss =
+ vmime::make_shared <vmime::utility::inputStreamStringAdapter>(str);
+
+ vmime::shared_ptr <vmime::utility::parserInputStreamAdapter> parser =
+ vmime::make_shared <vmime::utility::parserInputStreamAdapter>(iss);
+
+ VASSERT_EQ("Not found", vmime::string::npos, parser->findNext("token"));
+ }
+
+VMIME_TEST_SUITE_END
diff --git a/vmime-master/tests/utility/pathTest.cpp b/vmime-master/tests/utility/pathTest.cpp
new file mode 100644
index 0000000..e6227f3
--- /dev/null
+++ b/vmime-master/tests/utility/pathTest.cpp
@@ -0,0 +1,356 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "tests/testUtils.hpp"
+
+#include "vmime/utility/path.hpp"
+
+
+VMIME_TEST_SUITE_BEGIN(utilityPathTest)
+
+ VMIME_TEST_LIST_BEGIN
+ VMIME_TEST(testConstruct1)
+ VMIME_TEST(testConstruct2)
+ VMIME_TEST(testConstruct3)
+ VMIME_TEST(testConstruct4)
+
+ VMIME_TEST(testAppendComponent)
+
+ VMIME_TEST(testOperatorDiv1)
+ VMIME_TEST(testOperatorDiv2)
+
+ VMIME_TEST(testOperatorDivEqual1)
+ VMIME_TEST(testOperatorDivEqual2)
+
+ VMIME_TEST(testGetParent)
+
+ VMIME_TEST(testComparison)
+
+ VMIME_TEST(testGetLastComponent)
+
+ VMIME_TEST(testIsDirectParentOf)
+ VMIME_TEST(testIsParentOf)
+ VMIME_TEST(testIsParentOf_EquivalentCharset)
+
+ VMIME_TEST(testRenameParent)
+
+ VMIME_TEST(testFromString)
+ VMIME_TEST(testFromString_IgnoreLeadingOrTrailingSep)
+ VMIME_TEST(testToString)
+ VMIME_TEST_LIST_END
+
+
+ typedef vmime::utility::path path;
+ typedef vmime::utility::path::component comp;
+
+
+ void testConstruct1() {
+
+ VASSERT_EQ("1", true, path().isEmpty());
+ VASSERT_EQ("2", 0, path().getSize());
+ }
+
+ void testConstruct2() {
+
+ path p(comp("foo"));
+
+ VASSERT_EQ("1", false, p.isEmpty());
+ VASSERT_EQ("2", 1, p.getSize());
+ VASSERT_EQ("3", "foo", p.getComponentAt(0).getBuffer());
+ }
+
+ void testAppendComponent() {
+
+ path p;
+
+ VASSERT_EQ("1", 0, p.getSize());
+
+ comp c("foo");
+ p.appendComponent(c);
+
+ VASSERT_EQ("2", 1, p.getSize());
+ VASSERT_EQ("3", c.getBuffer(), p.getComponentAt(0).getBuffer());
+ }
+
+ void testConstruct3() {
+
+ path p1;
+ p1.appendComponent(comp("foo"));
+ p1.appendComponent(comp("bar"));
+
+ path p2(p1);
+
+ VASSERT_EQ("1", 2, p2.getSize());
+ VASSERT_EQ("2", "foo", p2.getComponentAt(0).getBuffer());
+ VASSERT_EQ("3", "bar", p2.getComponentAt(1).getBuffer());
+ }
+
+ void testConstruct4() {
+
+ // Same as path::path(const component&)
+ path p("foo");
+
+ VASSERT_EQ("1", false, p.isEmpty());
+ VASSERT_EQ("2", 1, p.getSize());
+ VASSERT_EQ("3", "foo", p.getComponentAt(0).getBuffer());
+ }
+
+ void testOperatorDiv1() {
+
+ path p1;
+ p1.appendComponent(comp("foo"));
+ p1.appendComponent(comp("bar"));
+
+ path p2;
+ p2.appendComponent(comp("baz"));
+
+ path p3 = p1 / p2;
+
+ VASSERT_EQ("1", 3, p3.getSize());
+ VASSERT_EQ("2", p1.getComponentAt(0).getBuffer(), p3.getComponentAt(0).getBuffer());
+ VASSERT_EQ("3", p1.getComponentAt(1).getBuffer(), p3.getComponentAt(1).getBuffer());
+ VASSERT_EQ("4", p2.getComponentAt(0).getBuffer(), p3.getComponentAt(2).getBuffer());
+ }
+
+ void testOperatorDiv2() {
+
+ path p1;
+ p1.appendComponent(comp("foo"));
+ p1.appendComponent(comp("bar"));
+
+ comp c("baz");
+
+ path p2 = p1 / c;
+
+ VASSERT_EQ("1", 3, p2.getSize());
+ VASSERT_EQ("2", p1.getComponentAt(0).getBuffer(), p2.getComponentAt(0).getBuffer());
+ VASSERT_EQ("3", p1.getComponentAt(1).getBuffer(), p2.getComponentAt(1).getBuffer());
+ VASSERT_EQ("4", c.getBuffer(), p2.getComponentAt(2).getBuffer());
+ }
+
+ void testOperatorDivEqual1() {
+
+ path p1;
+ p1.appendComponent(comp("foo"));
+ p1.appendComponent(comp("bar"));
+
+ path p2;
+ p2.appendComponent(comp("baz"));
+
+ path p3(p1);
+ p3 /= p2;
+
+ VASSERT_EQ("1", 3, p3.getSize());
+ VASSERT_EQ("2", p1.getComponentAt(0).getBuffer(), p3.getComponentAt(0).getBuffer());
+ VASSERT_EQ("3", p1.getComponentAt(1).getBuffer(), p3.getComponentAt(1).getBuffer());
+ VASSERT_EQ("4", p2.getComponentAt(0).getBuffer(), p3.getComponentAt(2).getBuffer());
+ }
+
+ void testOperatorDivEqual2() {
+
+ path p1;
+ p1.appendComponent(comp("foo"));
+ p1.appendComponent(comp("bar"));
+
+ comp c("baz");
+
+ path p2(p1);
+ p2 /= c;
+
+ VASSERT_EQ("1", 3, p2.getSize());
+ VASSERT_EQ("2", p1.getComponentAt(0).getBuffer(), p2.getComponentAt(0).getBuffer());
+ VASSERT_EQ("3", p1.getComponentAt(1).getBuffer(), p2.getComponentAt(1).getBuffer());
+ VASSERT_EQ("4", c.getBuffer(), p2.getComponentAt(2).getBuffer());
+ }
+
+ void testGetParent() {
+
+ path p1;
+ path p1p = p1.getParent();
+
+ VASSERT_EQ("1", true, p1p.isEmpty());
+
+ path p2;
+ p2.appendComponent(comp("foo"));
+ p2.appendComponent(comp("bar"));
+
+ path p2p = p2.getParent();
+
+ VASSERT_EQ("2", 1, p2p.getSize());
+ VASSERT_EQ("3", p2.getComponentAt(0).getBuffer(), p2p.getComponentAt(0).getBuffer());
+ }
+
+ void testComparison() {
+
+ path p1;
+ p1.appendComponent(comp("foo"));
+ p1.appendComponent(comp("bar"));
+
+ path p2;
+ p2.appendComponent(comp("foo"));
+ p2.appendComponent(comp("bar"));
+
+ path p3;
+ p3.appendComponent(comp("foo"));
+ p3.appendComponent(comp("bar"));
+ p3.appendComponent(comp("baz"));
+
+ VASSERT_EQ("1", true, p1 == p2);
+ VASSERT_EQ("2", false, p1 == p3);
+
+ VASSERT_EQ("3", false, p1 != p2);
+ VASSERT_EQ("4", true, p1 != p3);
+
+ VASSERT_EQ("5", true, p3.getParent() == p1);
+ }
+
+ void testGetLastComponent() {
+
+ path p1;
+ p1.appendComponent(comp("foo"));
+ p1.appendComponent(comp("bar"));
+ p1.appendComponent(comp("baz"));
+
+ VASSERT_EQ("1", "baz", p1.getLastComponent().getBuffer());
+ VASSERT_EQ("2", "bar", p1.getParent().getLastComponent().getBuffer());
+ VASSERT_EQ("3", "foo", p1.getParent().getParent().getLastComponent().getBuffer());
+ }
+
+ void testIsDirectParentOf() {
+
+ path p1;
+ p1.appendComponent(comp("foo"));
+
+ path p2;
+ p2.appendComponent(comp("foo"));
+ p2.appendComponent(comp("bar"));
+
+ path p3;
+ p3.appendComponent(comp("foo"));
+ p3.appendComponent(comp("bar"));
+ p3.appendComponent(comp("baz"));
+
+ VASSERT_EQ("1", true, p1.isDirectParentOf(p2));
+ VASSERT_EQ("2", true, p2.isDirectParentOf(p3));
+ VASSERT_EQ("3", false, p1.isDirectParentOf(p3));
+ VASSERT_EQ("4", false, p2.isDirectParentOf(p1));
+ }
+
+ void testIsParentOf() {
+
+ path p1;
+ p1.appendComponent(comp("foo"));
+
+ path p2;
+ p2.appendComponent(comp("foo"));
+ p2.appendComponent(comp("bar"));
+
+ path p3;
+ p3.appendComponent(comp("foo"));
+ p3.appendComponent(comp("bar"));
+ p3.appendComponent(comp("baz"));
+
+ VASSERT_EQ("1", true, p1.isParentOf(p2));
+ VASSERT_EQ("2", true, p2.isParentOf(p3));
+ VASSERT_EQ("3", true, p1.isParentOf(p3));
+ VASSERT_EQ("4", false, p2.isParentOf(p1));
+ }
+
+ void testIsParentOf_EquivalentCharset() {
+
+ path p1;
+ p1.appendComponent(comp("foo", "us-ascii"));
+
+ path p2;
+ p2.appendComponent(comp("foo", "utf-8"));
+ p2.appendComponent(comp("bar"));
+ p2.appendComponent(comp("baz"));
+
+ VASSERT_EQ("1", true, p1.isParentOf(p2));
+ }
+
+ void testRenameParent() {
+
+ path p1;
+ p1.appendComponent(comp("a"));
+ p1.appendComponent(comp("b"));
+ p1.appendComponent(comp("c"));
+ p1.appendComponent(comp("d"));
+
+ path p2;
+ p2.appendComponent(comp("a"));
+ p2.appendComponent(comp("b"));
+
+ path p3;
+ p3.appendComponent(comp("x"));
+ p3.appendComponent(comp("y"));
+ p3.appendComponent(comp("z"));
+
+ path p(p1);
+ p.renameParent(p2, p3);
+
+ VASSERT_EQ("1", 5, p.getSize());
+ VASSERT_EQ("2", "x", p.getComponentAt(0).getBuffer());
+ VASSERT_EQ("3", "y", p.getComponentAt(1).getBuffer());
+ VASSERT_EQ("4", "z", p.getComponentAt(2).getBuffer());
+ VASSERT_EQ("5", "c", p.getComponentAt(3).getBuffer());
+ VASSERT_EQ("6", "d", p.getComponentAt(4).getBuffer());
+ }
+
+ void testFromString() {
+
+ path p = path::fromString("ab/cde/f", "/", vmime::charset("my-charset"));
+
+ VASSERT_EQ("count", 3, p.getSize());
+ VASSERT_EQ("buffer1", "ab", p.getComponentAt(0).getBuffer());
+ VASSERT_EQ("charset1", "my-charset", p.getComponentAt(0).getCharset().getName());
+ VASSERT_EQ("buffer2", "cde", p.getComponentAt(1).getBuffer());
+ VASSERT_EQ("charset2", "my-charset", p.getComponentAt(1).getCharset().getName());
+ VASSERT_EQ("buffer3", "f", p.getComponentAt(2).getBuffer());
+ VASSERT_EQ("charset3", "my-charset", p.getComponentAt(2).getCharset().getName());
+ }
+
+ void testFromString_IgnoreLeadingOrTrailingSep() {
+
+ path p = path::fromString("//ab/cde/f////", "/", vmime::charset("my-charset"));
+
+ VASSERT_EQ("count", 3, p.getSize());
+ VASSERT_EQ("buffer1", "ab", p.getComponentAt(0).getBuffer());
+ VASSERT_EQ("charset1", "my-charset", p.getComponentAt(0).getCharset().getName());
+ VASSERT_EQ("buffer2", "cde", p.getComponentAt(1).getBuffer());
+ VASSERT_EQ("charset2", "my-charset", p.getComponentAt(1).getCharset().getName());
+ VASSERT_EQ("buffer3", "f", p.getComponentAt(2).getBuffer());
+ VASSERT_EQ("charset3", "my-charset", p.getComponentAt(2).getCharset().getName());
+ }
+
+ void testToString() {
+
+ path p;
+ p.appendComponent(comp("ab"));
+ p.appendComponent(comp("cde"));
+ p.appendComponent(comp("f"));
+
+ VASSERT_EQ("string", "ab/cde/f", p.toString("/", vmime::charset("us-ascii")));
+ }
+
+VMIME_TEST_SUITE_END
diff --git a/vmime-master/tests/utility/seekableInputStreamRegionAdapterTest.cpp b/vmime-master/tests/utility/seekableInputStreamRegionAdapterTest.cpp
new file mode 100644
index 0000000..b099cd7
--- /dev/null
+++ b/vmime-master/tests/utility/seekableInputStreamRegionAdapterTest.cpp
@@ -0,0 +1,176 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "tests/testUtils.hpp"
+
+#include "vmime/utility/inputStreamStringAdapter.hpp"
+#include "vmime/utility/seekableInputStreamRegionAdapter.hpp"
+#include "vmime/utility/stringUtils.hpp"
+
+
+using namespace vmime::utility;
+
+
+VMIME_TEST_SUITE_BEGIN(seekableInputStreamRegionAdapterTest)
+
+ VMIME_TEST_LIST_BEGIN
+ VMIME_TEST(testInitialPosition)
+ VMIME_TEST(testSeekAndGetPosition)
+ VMIME_TEST(testRead)
+ VMIME_TEST(testSkip)
+ VMIME_TEST(testReset)
+ VMIME_TEST(testOwnPosition)
+ VMIME_TEST_LIST_END
+
+
+ vmime::shared_ptr <seekableInputStreamRegionAdapter> createStream(
+ vmime::shared_ptr <seekableInputStream>* underlyingStream = NULL
+ ) {
+
+ vmime::string buffer("THIS IS A TEST BUFFER");
+
+ vmime::shared_ptr <seekableInputStream> strStream =
+ vmime::make_shared <inputStreamStringAdapter>(buffer);
+
+ vmime::shared_ptr <seekableInputStreamRegionAdapter> rgnStream =
+ vmime::make_shared <seekableInputStreamRegionAdapter>(strStream, 10, 11);
+
+ if (underlyingStream) {
+ *underlyingStream = strStream;
+ }
+
+ return rgnStream;
+ }
+
+ void testInitialPosition() {
+
+ vmime::shared_ptr <seekableInputStreamRegionAdapter> stream = createStream();
+
+ VASSERT_EQ("Pos", 0, stream->getPosition());
+ VASSERT_FALSE("EOF", stream->eof());
+ }
+
+ void testSeekAndGetPosition() {
+
+ vmime::shared_ptr <seekableInputStreamRegionAdapter> stream = createStream();
+
+ stream->seek(5);
+
+ VASSERT_EQ("Pos 1", 5, stream->getPosition());
+ VASSERT_FALSE("EOF 1", stream->eof());
+
+ stream->seek(20);
+
+ VASSERT_EQ("Pos 2", 11, stream->getPosition());
+ VASSERT_TRUE("EOF 2", stream->eof());
+ }
+
+ void testRead() {
+
+ vmime::shared_ptr <seekableInputStreamRegionAdapter> stream = createStream();
+
+ stream->seek(5);
+
+ vmime::byte_t buffer[100];
+ std::fill(vmime::begin(buffer), vmime::end(buffer), 0);
+ vmime::size_t read = stream->read(buffer, 6);
+
+ VASSERT_EQ("Pos", 11, stream->getPosition());
+ VASSERT_EQ("Read", 6, read);
+ VASSERT_TRUE("EOF", stream->eof());
+ VASSERT_EQ("Buffer", "BUFFER", vmime::utility::stringUtils::makeStringFromBytes(buffer, 6));
+ }
+
+ void testSkip() {
+
+ vmime::shared_ptr <seekableInputStreamRegionAdapter> stream = createStream();
+
+ stream->skip(5);
+
+ VASSERT_EQ("Pos 1", 5, stream->getPosition());
+ VASSERT_FALSE("EOF 1", stream->eof());
+
+ vmime::byte_t buffer[100];
+ std::fill(vmime::begin(buffer), vmime::end(buffer), 0);
+ vmime::size_t read = stream->read(buffer, 3);
+
+ VASSERT_EQ("Pos 2", 8, stream->getPosition());
+ VASSERT_EQ("Read", 3, read);
+ VASSERT_FALSE("EOF 2", stream->eof());
+ VASSERT_EQ("Buffer", "BUF", vmime::utility::stringUtils::makeStringFromBytes(buffer, 3));
+
+ stream->skip(50);
+
+ VASSERT_EQ("Pos 3", 11, stream->getPosition());
+ VASSERT_TRUE("EOF 3", stream->eof());
+ }
+
+ void testReset() {
+
+ vmime::shared_ptr <seekableInputStreamRegionAdapter> stream = createStream();
+
+ stream->skip(100);
+ stream->reset();
+
+ VASSERT_EQ("Pos", 0, stream->getPosition());
+ VASSERT_FALSE("EOF", stream->eof());
+ }
+
+ void testOwnPosition() {
+
+ // seekableInputStreamRegionAdapter should keep track of its own position
+ // in the underlying stream, and not be affected by possible seek/read
+ // operations on it...
+ vmime::shared_ptr <seekableInputStream> ustream;
+ vmime::shared_ptr <seekableInputStreamRegionAdapter> stream = createStream(&ustream);
+
+ stream->seek(5);
+
+ vmime::byte_t buffer1[100];
+ std::fill(vmime::begin(buffer1), vmime::end(buffer1), 0);
+
+ VASSERT_EQ("Read 1", 7, ustream->read(buffer1, 7));
+
+ vmime::byte_t buffer2[100];
+ std::fill(vmime::begin(buffer2), vmime::end(buffer2), 0);
+
+ VASSERT_EQ("Read 2", 6, stream->read(buffer2, 6));
+
+ VASSERT_EQ(
+ "Buffer 1",
+ "THIS IS",
+ vmime::utility::stringUtils::makeStringFromBytes(buffer1, 7)
+ );
+
+ VASSERT_EQ(
+ "Buffer 2",
+ "BUFFER",
+ vmime::utility::stringUtils::makeStringFromBytes(buffer2, 6)
+ );
+
+ // ...but the underlying stream position is affected by read operations
+ // from the region adapter (FIXME?)
+ VASSERT_EQ("Pos", 21, ustream->getPosition());
+ }
+
+VMIME_TEST_SUITE_END
diff --git a/vmime-master/tests/utility/stringUtilsTest.cpp b/vmime-master/tests/utility/stringUtilsTest.cpp
new file mode 100644
index 0000000..6c2e18f
--- /dev/null
+++ b/vmime-master/tests/utility/stringUtilsTest.cpp
@@ -0,0 +1,214 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "tests/testUtils.hpp"
+
+#include "vmime/utility/stringUtils.hpp"
+
+
+VMIME_TEST_SUITE_BEGIN(stringUtilsTest)
+
+ VMIME_TEST_LIST_BEGIN
+ VMIME_TEST(testMakeStringFromBytes)
+ VMIME_TEST(testAppendBytesToString)
+
+ VMIME_TEST(testIsStringEqualNoCase1)
+ VMIME_TEST(testIsStringEqualNoCase2)
+ VMIME_TEST(testIsStringEqualNoCase3)
+
+ VMIME_TEST(testToLower)
+
+ VMIME_TEST(testTrim)
+
+ VMIME_TEST(testCountASCIIChars)
+
+ VMIME_TEST(testUnquote)
+
+ VMIME_TEST(testIsValidHostname)
+ VMIME_TEST(testIsValidFQDN)
+ VMIME_TEST_LIST_END
+
+
+ typedef vmime::utility::stringUtils stringUtils;
+
+
+ void testMakeStringFromBytes() {
+
+ vmime::byte_t bytes[] = { 0x12, 0x34, 0x56, 0x78 };
+ vmime::string str = vmime::utility::stringUtils::makeStringFromBytes(bytes, 3);
+
+ VASSERT_EQ("length", 3, str.length());
+ VASSERT_EQ("byte1", '\x12', str[0]);
+ VASSERT_EQ("byte2", '\x34', str[1]);
+ VASSERT_EQ("byte3", '\x56', str[2]);
+ }
+
+ void testAppendBytesToString() {
+
+ vmime::byte_t bytes[] = { 0x42, 0x56, 0x12, 0x00, 'f', 'o', 'o' };
+
+ vmime::string str = "test";
+ vmime::utility::stringUtils::appendBytesToString(str, bytes, 7);
+
+ VASSERT_EQ("length", 4 + 7, str.length());
+ VASSERT_EQ("byte1", 't', str[0]);
+ VASSERT_EQ("byte2", 'e', str[1]);
+ VASSERT_EQ("byte3", 's', str[2]);
+ VASSERT_EQ("byte4", 't', str[3]);
+ VASSERT_EQ("byte5", '\x42', str[4]);
+ VASSERT_EQ("byte6", '\x56', str[5]);
+ VASSERT_EQ("byte7", '\x12', str[6]);
+ VASSERT_EQ("byte8", '\0', str[7]);
+ VASSERT_EQ("byte9", 'f', str[8]);
+ VASSERT_EQ("byte10", 'o', str[9]);
+ VASSERT_EQ("byte11", 'o', str[10]);
+ }
+
+ void testIsStringEqualNoCase1() {
+
+ VASSERT_EQ("1", true, stringUtils::isStringEqualNoCase(vmime::string("foo"), "foo", 3));
+ VASSERT_EQ("2", true, stringUtils::isStringEqualNoCase(vmime::string("FOo"), "foo", 3));
+
+ VASSERT_EQ("3", false, stringUtils::isStringEqualNoCase(vmime::string("foo"), "FOo", 3));
+ VASSERT_EQ("4", false, stringUtils::isStringEqualNoCase(vmime::string("foo"), "bar", 3));
+
+ VASSERT_EQ("5", false, stringUtils::isStringEqualNoCase(vmime::string("foO"), "bar", 3));
+ VASSERT_EQ("6", false, stringUtils::isStringEqualNoCase(vmime::string("foOO"), "barO", 4));
+ VASSERT_EQ("7", false, stringUtils::isStringEqualNoCase(vmime::string("foOO"), "ba", 2));
+
+ VASSERT_EQ("8", true, stringUtils::isStringEqualNoCase(vmime::string("FOoooo"), "foo", 3));
+ }
+
+ void testIsStringEqualNoCase2() {
+
+ VASSERT_EQ("1", true, stringUtils::isStringEqualNoCase(vmime::string("foo"), vmime::string("foo")));
+ VASSERT_EQ("2", true, stringUtils::isStringEqualNoCase(vmime::string("FOo"), vmime::string("foo")));
+ VASSERT_EQ("3", true, stringUtils::isStringEqualNoCase(vmime::string("foO"), vmime::string("FOo")));
+
+ VASSERT_EQ("4", false, stringUtils::isStringEqualNoCase(vmime::string("foO"), vmime::string("bar")));
+ VASSERT_EQ("5", false, stringUtils::isStringEqualNoCase(vmime::string("foOO"), vmime::string("barO")));
+ }
+
+ void testIsStringEqualNoCase3() {
+
+ vmime::string str1("FooBar");
+
+ VASSERT_EQ("1", true, stringUtils::isStringEqualNoCase(str1.begin(), str1.end(), "foobar", 6));
+ VASSERT_EQ("2", false, stringUtils::isStringEqualNoCase(str1.begin(), str1.end(), "FooBar", 6));
+ VASSERT_EQ("3", true, stringUtils::isStringEqualNoCase(str1.begin(), str1.end(), "fooBar", 3));
+ VASSERT_EQ("4", false, stringUtils::isStringEqualNoCase(str1.begin(), str1.begin() + 3, "fooBar", 6));
+ VASSERT_EQ("5", false, stringUtils::isStringEqualNoCase(str1.begin(), str1.begin() + 3, "bar", 3));
+ VASSERT_EQ("6", false, stringUtils::isStringEqualNoCase(str1.begin(), str1.begin() + 6, "barbar", 6));
+ }
+
+ void testToLower() {
+
+ VASSERT_EQ("1", "foo", stringUtils::toLower("FOO"));
+ VASSERT_EQ("2", "foo", stringUtils::toLower("foO"));
+ VASSERT_EQ("3", "foo", stringUtils::toLower("foo"));
+ }
+
+ void testTrim() {
+
+ VASSERT_EQ("1", "foo", stringUtils::trim(" foo"));
+ VASSERT_EQ("2", "foo", stringUtils::trim("\t\tfoo"));
+ VASSERT_EQ("3", "foo", stringUtils::trim(" \t \tfoo"));
+ VASSERT_EQ("4", "foo", stringUtils::trim(" \r\n\tfoo"));
+
+ VASSERT_EQ("5", "foo", stringUtils::trim("foo "));
+ VASSERT_EQ("6", "foo", stringUtils::trim("foo\t\t"));
+ VASSERT_EQ("7", "foo", stringUtils::trim("foo \t \t"));
+ VASSERT_EQ("8", "foo", stringUtils::trim("foo \r\n\t"));
+
+ VASSERT_EQ( "9", "foo", stringUtils::trim("foo "));
+ VASSERT_EQ("10", "foo", stringUtils::trim(" foo "));
+ VASSERT_EQ("11", "foo", stringUtils::trim(" foo\t\t"));
+ VASSERT_EQ("12", "foo", stringUtils::trim("\tfoo \r \t"));
+ VASSERT_EQ("13", "foo", stringUtils::trim("\r \tfoo \n\t"));
+ }
+
+ void testCountASCIIChars() {
+
+ vmime::string str1("foo");
+ VASSERT_EQ(
+ "1",
+ static_cast <vmime::size_t>(3),
+ stringUtils::countASCIIchars(str1.begin(), str1.end())
+ );
+
+ vmime::string str2("f=?oo");
+ VASSERT_EQ(
+ "2",
+ static_cast <vmime::size_t>(3 + 1),
+ stringUtils::countASCIIchars(str2.begin(), str2.end())
+ );
+
+ vmime::string str3("foo\x7f");
+ VASSERT_EQ(
+ "3",
+ static_cast <vmime::size_t>(4),
+ stringUtils::countASCIIchars(str3.begin(), str3.end())
+ );
+
+ vmime::string str4("foo\x80");
+ VASSERT_EQ(
+ "4",
+ static_cast <vmime::size_t>(3),
+ stringUtils::countASCIIchars(str4.begin(), str4.end())
+ );
+ }
+
+ void testUnquote() {
+
+ VASSERT_EQ("1", "quoted", stringUtils::unquote("\"quoted\"")); // "quoted"
+ VASSERT_EQ("2", "\"not quoted", stringUtils::unquote("\"not quoted")); // "not quoted
+ VASSERT_EQ("3", "not quoted\"", stringUtils::unquote("not quoted\"")); // not quoted"
+ VASSERT_EQ("4", "quoted with \"escape\"", stringUtils::unquote("\"quoted with \\\"escape\\\"\"")); // "quoted with \"escape\""
+ }
+
+ void testIsValidHostname() {
+
+ VASSERT_TRUE ("1", stringUtils::isValidHostname("localhost"));
+ VASSERT_TRUE ("2", stringUtils::isValidHostname("localhost.localdomain"));
+ VASSERT_TRUE ("3", stringUtils::isValidHostname("example.com"));
+ VASSERT_TRUE ("4", stringUtils::isValidHostname("host.example.com"));
+ VASSERT_FALSE("5", stringUtils::isValidHostname(".example.com"));
+ VASSERT_FALSE("6", stringUtils::isValidHostname(".-example.com"));
+ VASSERT_FALSE("7", stringUtils::isValidHostname(".example-.com"));
+ VASSERT_FALSE("8", stringUtils::isValidHostname(".exa--mple.com"));
+ VASSERT_FALSE("9", stringUtils::isValidHostname("-example.com"));
+ }
+
+ void testIsValidFQDN() {
+
+ VASSERT_FALSE("1", stringUtils::isValidFQDN("localhost"));
+ VASSERT_FALSE("2", stringUtils::isValidFQDN("localhost.localdomain"));
+ VASSERT_FALSE("3", stringUtils::isValidFQDN("example.com"));
+ VASSERT_TRUE ("4", stringUtils::isValidFQDN("host.example.com"));
+ VASSERT_FALSE("5", stringUtils::isValidFQDN(".example.com"));
+ VASSERT_FALSE("6", stringUtils::isValidFQDN(".-example.com"));
+ VASSERT_FALSE("7", stringUtils::isValidFQDN(".example-.com"));
+ VASSERT_FALSE("8", stringUtils::isValidFQDN(".exa--mple.com"));
+ }
+
+VMIME_TEST_SUITE_END
diff --git a/vmime-master/tests/utility/urlTest.cpp b/vmime-master/tests/utility/urlTest.cpp
new file mode 100644
index 0000000..36820a6
--- /dev/null
+++ b/vmime-master/tests/utility/urlTest.cpp
@@ -0,0 +1,312 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "tests/testUtils.hpp"
+
+#include "vmime/utility/url.hpp"
+#include "vmime/utility/urlUtils.hpp"
+
+
+VMIME_TEST_SUITE_BEGIN(urlTest)
+
+ VMIME_TEST_LIST_BEGIN
+ VMIME_TEST(testParse1)
+ VMIME_TEST(testParse2)
+ VMIME_TEST(testParse3)
+ VMIME_TEST(testParse4)
+ VMIME_TEST(testParse5)
+ VMIME_TEST(testGenerate)
+ VMIME_TEST(testUtilsEncode)
+ VMIME_TEST(testUtilsDecode)
+ VMIME_TEST(testUtilsDecodeSpecialCases)
+ VMIME_TEST(testUtilsEncodeReservedChars)
+ VMIME_TEST(testUtilsEncodeUnsafeChars)
+ VMIME_TEST_LIST_END
+
+
+ static bool parseHelper(vmime::utility::url& u, const vmime::string& str) {
+
+ try {
+
+ u = vmime::utility::url(str);
+
+ } catch (vmime::exceptions::malformed_url) {
+
+ return false;
+ }
+
+ return true;
+ }
+
+
+ void testParse1() {
+
+ // Test some valid constructions
+ vmime::utility::url u1("", "");
+
+ VASSERT_EQ("1.1", true, parseHelper(u1, "protocol://user:password@host:12345/path/"));
+ VASSERT_EQ("1.2", "protocol", u1.getProtocol());
+ VASSERT_EQ("1.3", "user", u1.getUsername());
+ VASSERT_EQ("1.4", "password", u1.getPassword());
+ VASSERT_EQ("1.5", "host", u1.getHost());
+ VASSERT_EQ("1.6", 12345, u1.getPort());
+ VASSERT_EQ("1.7", "/path/", u1.getPath());
+
+ vmime::utility::url u2("", "");
+
+ VASSERT_EQ("2.1", true, parseHelper(u2, "protocol://user@host:12345/path/"));
+ VASSERT_EQ("2.2", "protocol", u2.getProtocol());
+ VASSERT_EQ("2.3", "user", u2.getUsername());
+ VASSERT_EQ("2.4", "", u2.getPassword());
+ VASSERT_EQ("2.5", "host", u2.getHost());
+ VASSERT_EQ("2.6", 12345, u2.getPort());
+ VASSERT_EQ("2.7", "/path/", u2.getPath());
+
+ vmime::utility::url u3("", "");
+
+ VASSERT_EQ("3.1", true, parseHelper(u3, "protocol://host:12345/path/"));
+ VASSERT_EQ("3.2", "protocol", u3.getProtocol());
+ VASSERT_EQ("3.3", "", u3.getUsername());
+ VASSERT_EQ("3.4", "", u3.getPassword());
+ VASSERT_EQ("3.5", "host", u3.getHost());
+ VASSERT_EQ("3.6", 12345, u3.getPort());
+ VASSERT_EQ("3.7", "/path/", u3.getPath());
+
+ vmime::utility::url u4("", "");
+
+ VASSERT_EQ("4.1", true, parseHelper(u4, "protocol://host/path/"));
+ VASSERT_EQ("4.2", "protocol", u4.getProtocol());
+ VASSERT_EQ("4.3", "", u4.getUsername());
+ VASSERT_EQ("4.4", "", u4.getPassword());
+ VASSERT_EQ("4.5", "host", u4.getHost());
+ VASSERT_EQ("4.6", vmime::utility::url::UNSPECIFIED_PORT, u4.getPort());
+ VASSERT_EQ("4.7", "/path/", u4.getPath());
+
+ vmime::utility::url u5("", "");
+
+ VASSERT_EQ("5.1", true, parseHelper(u5, "protocol://host/"));
+ VASSERT_EQ("5.2", "protocol", u5.getProtocol());
+ VASSERT_EQ("5.3", "", u5.getUsername());
+ VASSERT_EQ("5.4", "", u5.getPassword());
+ VASSERT_EQ("5.5", "host", u5.getHost());
+ VASSERT_EQ("5.6", vmime::utility::url::UNSPECIFIED_PORT, u4.getPort());
+ VASSERT_EQ("5.7", "", u5.getPath());
+
+ vmime::utility::url u6("", "");
+
+ VASSERT_EQ("6.1", true, parseHelper(u4, "protocol://host/path/file"));
+ VASSERT_EQ("6.2", "protocol", u4.getProtocol());
+ VASSERT_EQ("6.3", "", u4.getUsername());
+ VASSERT_EQ("6.4", "", u4.getPassword());
+ VASSERT_EQ("6.5", "host", u4.getHost());
+ VASSERT_EQ("6.6", vmime::utility::url::UNSPECIFIED_PORT, u4.getPort());
+ VASSERT_EQ("6.7", "/path/file", u4.getPath());
+ }
+
+ void testParse2() {
+
+ // Now, test some ill-formed URLs
+
+ // -- missing protocol
+ vmime::utility::url u1("", "");
+ VASSERT_EQ("1", false, parseHelper(u1, "://host"));
+
+ // -- port can contain only digits
+ vmime::utility::url u2("", "");
+ VASSERT_EQ("2", false, parseHelper(u2, "proto://host:abc123"));
+
+ // -- no host specified
+ vmime::utility::url u3("", "");
+ VASSERT_EQ("3", false, parseHelper(u3, "proto:///path"));
+
+ // -- no protocol separator (://)
+ vmime::utility::url u4("", "");
+ VASSERT_EQ("4", false, parseHelper(u4, "protohost/path"));
+ }
+
+ void testParse3() {
+
+ // Test decoding
+ vmime::utility::url u1("", "");
+
+ VASSERT_EQ("1.1", true, parseHelper(u1, "pro%12to://user%34:pass%56word@ho%78st:12345/pa%abth/"));
+ VASSERT_EQ("1.2", "pro%12to", u1.getProtocol()); // protocol should not be decoded
+ VASSERT_EQ("1.3", "user\x34", u1.getUsername());
+ VASSERT_EQ("1.4", "pass\x56word", u1.getPassword());
+ VASSERT_EQ("1.5", "ho\x78st", u1.getHost());
+ VASSERT_EQ("1.6", 12345, u1.getPort());
+ VASSERT_EQ("1.7", "/pa\xabth/", u1.getPath());
+ }
+
+ void testParse4() {
+
+ // Test parameters
+ vmime::utility::url u1("", "");
+
+ VASSERT_EQ("1.1", true, parseHelper(u1, "proto://host/path?p1=v1&p2=v2"));
+ VASSERT_EQ("1.2", "v1", u1.getParams()["p1"]);
+ VASSERT_EQ("1.3", "v2", u1.getParams()["p2"]);
+ VASSERT_EQ("1.4", "/path", u1.getPath());
+
+ vmime::utility::url u2("", "");
+
+ VASSERT_EQ("2.1", true, parseHelper(u2, "proto://host/path?p1=v1&p2"));
+ VASSERT_EQ("2.2", "v1", u2.getParams()["p1"]);
+ VASSERT_EQ("2.3", "p2", u2.getParams()["p2"]);
+ VASSERT_EQ("2.4", "/path", u2.getPath());
+
+ vmime::utility::url u3("", "");
+
+ VASSERT_EQ("3.1", true, parseHelper(u3, "proto://host/?p1=v1&p2=v2"));
+ VASSERT_EQ("3.2", "v1", u3.getParams()["p1"]);
+ VASSERT_EQ("3.3", "v2", u3.getParams()["p2"]);
+ VASSERT_EQ("3.4", "", u3.getPath());
+
+ vmime::utility::url u4("", "");
+
+ VASSERT_EQ("4.1", true, parseHelper(u4, "proto://host/path?p1=%3D&%3D=v2"));
+ VASSERT_EQ("4.2", "=", u4.getParams()["p1"]);
+ VASSERT_EQ("4.3", "v2", u4.getParams()["="]);
+ VASSERT_EQ("4.4", "/path", u4.getPath());
+ }
+
+ // '@' symbol in the username part
+ void testParse5() {
+
+ vmime::utility::url u1("", "");
+
+ VASSERT_EQ("1", true, parseHelper(u1, "imap://account@myserver.com:password@myserver.com"));
+ VASSERT_EQ("2", "account@myserver.com", u1.getUsername());
+ VASSERT_EQ("3", "password", u1.getPassword());
+ VASSERT_EQ("4", "myserver.com", u1.getHost());
+ }
+
+ void testGenerate() {
+
+ vmime::utility::url u1("proto", "host", 12345, "path", "user", "password");
+ VASSERT_EQ(
+ "1",
+ "proto://user:password@host:12345/path",
+ static_cast <vmime::string>(u1)
+ );
+
+ vmime::utility::url u2("proto", "host");
+ VASSERT_EQ("2", "proto://host", static_cast <vmime::string>(u2));
+
+ vmime::utility::url u3("proto", "host");
+ u3.getParams()["p1"] = "v1";
+ VASSERT_EQ(
+ "3.1",
+ "proto://host/?p1=v1",
+ static_cast <vmime::string>(u3)
+ );
+ u3.getParams()["p2"] = "v2";
+ VASSERT_EQ(
+ "3.2",
+ "proto://host/?p1=v1&p2=v2",
+ static_cast <vmime::string>(u3)
+ );
+
+ // Test special characters
+ u3.getParams().clear();
+ u3.getParams()["&"] = "=";
+ VASSERT_EQ(
+ "3.3",
+ "proto://host/?%26=%3D",
+ static_cast <vmime::string>(u3)
+ );
+ }
+
+ void testUtilsEncode() {
+
+ VASSERT_EQ("1", "%01", vmime::utility::urlUtils::encode("\x01"));
+ VASSERT_EQ("2", "%20", vmime::utility::urlUtils::encode(" "));
+ VASSERT_EQ("3", "%FF", vmime::utility::urlUtils::encode("\xff"));
+ VASSERT_EQ("4", "a", vmime::utility::urlUtils::encode("a"));
+ }
+
+ void testUtilsDecode() {
+
+ for (int i = 0 ; i < 255 ; ++i) {
+
+ std::ostringstream ossTest;
+ ossTest << "%" << "0123456789ABCDEF"[i / 16]
+ << "0123456789ABCDEF"[i % 16];
+
+ std::ostringstream ossNum;
+ ossNum << i;
+
+ vmime::string res;
+ res += static_cast <unsigned char>(i);
+
+ VASSERT_EQ(
+ ossNum.str(),
+ res,
+ vmime::utility::urlUtils::decode(ossTest.str())
+ );
+ }
+
+ }
+
+ void testUtilsDecodeSpecialCases() {
+
+ // Bug #1656547: segfault with '%' at the end of the string
+ VASSERT_EQ("1.1", "sadfsda%", vmime::utility::urlUtils::decode("sadfsda%"));
+ VASSERT_EQ("1.2", "sadfsda\x05", vmime::utility::urlUtils::decode("sadfsda%5"));
+ VASSERT_EQ("1.3", "sadfsda\x42", vmime::utility::urlUtils::decode("sadfsda%42"));
+ }
+
+ void testUtilsEncodeReservedChars() {
+
+ VASSERT_EQ("1", "%24", vmime::utility::urlUtils::encode("$"));
+ VASSERT_EQ("2", "%26", vmime::utility::urlUtils::encode("&"));
+ VASSERT_EQ("3", "%2B", vmime::utility::urlUtils::encode("+"));
+ VASSERT_EQ("4", "%2C", vmime::utility::urlUtils::encode(","));
+ VASSERT_EQ("5", "%2F", vmime::utility::urlUtils::encode("/"));
+ VASSERT_EQ("6", "%3A", vmime::utility::urlUtils::encode(":"));
+ VASSERT_EQ("7", "%3B", vmime::utility::urlUtils::encode(";"));
+ VASSERT_EQ("8", "%3D", vmime::utility::urlUtils::encode("="));
+ VASSERT_EQ("9", "%3F", vmime::utility::urlUtils::encode("?"));
+ VASSERT_EQ("10", "%40", vmime::utility::urlUtils::encode("@"));
+ }
+
+ void testUtilsEncodeUnsafeChars() {
+
+ VASSERT_EQ("1", "%20", vmime::utility::urlUtils::encode(" "));
+ VASSERT_EQ("2", "%22", vmime::utility::urlUtils::encode("\""));
+ VASSERT_EQ("3", "%3C", vmime::utility::urlUtils::encode("<"));
+ VASSERT_EQ("4", "%3E", vmime::utility::urlUtils::encode(">"));
+ VASSERT_EQ("5", "%23", vmime::utility::urlUtils::encode("#"));
+ VASSERT_EQ("6", "%25", vmime::utility::urlUtils::encode("%"));
+ VASSERT_EQ("7", "%7B", vmime::utility::urlUtils::encode("{"));
+ VASSERT_EQ("8", "%7D", vmime::utility::urlUtils::encode("}"));
+ VASSERT_EQ("9", "%7C", vmime::utility::urlUtils::encode("|"));
+ VASSERT_EQ("10", "%5C", vmime::utility::urlUtils::encode("\\"));
+ VASSERT_EQ("11", "%5E", vmime::utility::urlUtils::encode("^"));
+ VASSERT_EQ("12", "%7E", vmime::utility::urlUtils::encode("~"));
+ VASSERT_EQ("13", "%5B", vmime::utility::urlUtils::encode("["));
+ VASSERT_EQ("14", "%5D", vmime::utility::urlUtils::encode("]"));
+ VASSERT_EQ("15", "%60", vmime::utility::urlUtils::encode("`"));
+ }
+
+VMIME_TEST_SUITE_END