From aa4d426b4d3527d7e166df1a05058c9a4a0f6683 Mon Sep 17 00:00:00 2001 From: Wojtek Kosior Date: Fri, 30 Apr 2021 00:33:56 +0200 Subject: initial/final commit --- vmime-master/tests/misc/importanceHelperTest.cpp | 191 +++++ vmime-master/tests/net/folderAttributesTest.cpp | 137 +++ vmime-master/tests/net/imap/IMAPCommandTest.cpp | 495 +++++++++++ vmime-master/tests/net/imap/IMAPParserTest.cpp | 374 +++++++++ vmime-master/tests/net/imap/IMAPTagTest.cpp | 90 ++ vmime-master/tests/net/imap/IMAPUtilsTest.cpp | 283 +++++++ .../tests/net/maildir/maildirStoreTest.cpp | 584 +++++++++++++ .../tests/net/maildir/maildirUtilsTest.cpp | 54 ++ vmime-master/tests/net/messageSetTest.cpp | 229 +++++ vmime-master/tests/net/pop3/POP3CommandTest.cpp | 241 ++++++ vmime-master/tests/net/pop3/POP3ResponseTest.cpp | 244 ++++++ vmime-master/tests/net/pop3/POP3StoreTest.cpp | 67 ++ vmime-master/tests/net/pop3/POP3TestUtils.hpp | 69 ++ vmime-master/tests/net/pop3/POP3UtilsTest.cpp | 88 ++ vmime-master/tests/net/smtp/SMTPCommandSetTest.cpp | 181 ++++ vmime-master/tests/net/smtp/SMTPCommandTest.cpp | 252 ++++++ vmime-master/tests/net/smtp/SMTPResponseTest.cpp | 238 ++++++ vmime-master/tests/net/smtp/SMTPTransportTest.cpp | 324 ++++++++ .../tests/net/smtp/SMTPTransportTestUtils.hpp | 792 ++++++++++++++++++ vmime-master/tests/parser/attachmentHelperTest.cpp | 335 ++++++++ vmime-master/tests/parser/bodyPartTest.cpp | 414 ++++++++++ vmime-master/tests/parser/bodyTest.cpp | 79 ++ .../parser/charsetFilteredOutputStreamTest.cpp | 213 +++++ vmime-master/tests/parser/charsetTest.cpp | 252 ++++++ vmime-master/tests/parser/charsetTestSuites.hpp | 102 +++ vmime-master/tests/parser/datetimeTest.cpp | 123 +++ vmime-master/tests/parser/dispositionTest.cpp | 150 ++++ vmime-master/tests/parser/emailAddressTest.cpp | 281 +++++++ .../tests/parser/emptyContentHandlerTest.cpp | 99 +++ .../tests/parser/fileContentHandlerTest.cpp | 134 +++ vmime-master/tests/parser/headerFieldTest.cpp | 112 +++ vmime-master/tests/parser/headerTest.cpp | 375 +++++++++ vmime-master/tests/parser/htmlTextPartTest.cpp | 241 ++++++ vmime-master/tests/parser/mailboxGroupTest.cpp | 107 +++ vmime-master/tests/parser/mailboxListTest.cpp | 47 ++ vmime-master/tests/parser/mailboxTest.cpp | 187 +++++ vmime-master/tests/parser/mediaTypeTest.cpp | 100 +++ .../tests/parser/messageIdSequenceTest.cpp | 78 ++ vmime-master/tests/parser/messageIdTest.cpp | 77 ++ vmime-master/tests/parser/messageTest.cpp | 64 ++ vmime-master/tests/parser/parameterTest.cpp | 722 ++++++++++++++++ vmime-master/tests/parser/pathTest.cpp | 102 +++ .../tests/parser/streamContentHandlerTest.cpp | 194 +++++ .../tests/parser/stringContentHandlerTest.cpp | 165 ++++ vmime-master/tests/parser/textTest.cpp | 918 +++++++++++++++++++++ vmime-master/tests/parser/wordEncoderTest.cpp | 174 ++++ vmime-master/tests/security/digest/md5Test.cpp | 228 +++++ vmime-master/tests/security/digest/sha1Test.cpp | 119 +++ vmime-master/tests/testRunner.cpp | 305 +++++++ vmime-master/tests/testUtils.cpp | 404 +++++++++ vmime-master/tests/testUtils.hpp | 407 +++++++++ vmime-master/tests/utility/datetimeUtilsTest.cpp | 157 ++++ .../tests/utility/encoder/b64EncoderTest.cpp | 168 ++++ .../tests/utility/encoder/encoderFactoryTest.cpp | 63 ++ .../tests/utility/encoder/encoderTestUtils.hpp | 82 ++ .../tests/utility/encoder/qpEncoderTest.cpp | 275 ++++++ vmime-master/tests/utility/filteredStreamTest.cpp | 341 ++++++++ .../utility/outputStreamByteArrayAdapterTest.cpp | 82 ++ .../utility/outputStreamSocketAdapterTest.cpp | 87 ++ .../utility/outputStreamStringAdapterTest.cpp | 84 ++ .../tests/utility/parserInputStreamAdapterTest.cpp | 51 ++ vmime-master/tests/utility/pathTest.cpp | 356 ++++++++ .../seekableInputStreamRegionAdapterTest.cpp | 176 ++++ vmime-master/tests/utility/stringUtilsTest.cpp | 214 +++++ vmime-master/tests/utility/urlTest.cpp | 312 +++++++ 65 files changed, 14689 insertions(+) create mode 100644 vmime-master/tests/misc/importanceHelperTest.cpp create mode 100644 vmime-master/tests/net/folderAttributesTest.cpp create mode 100644 vmime-master/tests/net/imap/IMAPCommandTest.cpp create mode 100644 vmime-master/tests/net/imap/IMAPParserTest.cpp create mode 100644 vmime-master/tests/net/imap/IMAPTagTest.cpp create mode 100644 vmime-master/tests/net/imap/IMAPUtilsTest.cpp create mode 100644 vmime-master/tests/net/maildir/maildirStoreTest.cpp create mode 100644 vmime-master/tests/net/maildir/maildirUtilsTest.cpp create mode 100644 vmime-master/tests/net/messageSetTest.cpp create mode 100644 vmime-master/tests/net/pop3/POP3CommandTest.cpp create mode 100644 vmime-master/tests/net/pop3/POP3ResponseTest.cpp create mode 100644 vmime-master/tests/net/pop3/POP3StoreTest.cpp create mode 100644 vmime-master/tests/net/pop3/POP3TestUtils.hpp create mode 100644 vmime-master/tests/net/pop3/POP3UtilsTest.cpp create mode 100644 vmime-master/tests/net/smtp/SMTPCommandSetTest.cpp create mode 100644 vmime-master/tests/net/smtp/SMTPCommandTest.cpp create mode 100644 vmime-master/tests/net/smtp/SMTPResponseTest.cpp create mode 100644 vmime-master/tests/net/smtp/SMTPTransportTest.cpp create mode 100644 vmime-master/tests/net/smtp/SMTPTransportTestUtils.hpp create mode 100644 vmime-master/tests/parser/attachmentHelperTest.cpp create mode 100644 vmime-master/tests/parser/bodyPartTest.cpp create mode 100644 vmime-master/tests/parser/bodyTest.cpp create mode 100644 vmime-master/tests/parser/charsetFilteredOutputStreamTest.cpp create mode 100644 vmime-master/tests/parser/charsetTest.cpp create mode 100644 vmime-master/tests/parser/charsetTestSuites.hpp create mode 100644 vmime-master/tests/parser/datetimeTest.cpp create mode 100644 vmime-master/tests/parser/dispositionTest.cpp create mode 100644 vmime-master/tests/parser/emailAddressTest.cpp create mode 100644 vmime-master/tests/parser/emptyContentHandlerTest.cpp create mode 100644 vmime-master/tests/parser/fileContentHandlerTest.cpp create mode 100644 vmime-master/tests/parser/headerFieldTest.cpp create mode 100644 vmime-master/tests/parser/headerTest.cpp create mode 100644 vmime-master/tests/parser/htmlTextPartTest.cpp create mode 100644 vmime-master/tests/parser/mailboxGroupTest.cpp create mode 100644 vmime-master/tests/parser/mailboxListTest.cpp create mode 100644 vmime-master/tests/parser/mailboxTest.cpp create mode 100644 vmime-master/tests/parser/mediaTypeTest.cpp create mode 100644 vmime-master/tests/parser/messageIdSequenceTest.cpp create mode 100644 vmime-master/tests/parser/messageIdTest.cpp create mode 100644 vmime-master/tests/parser/messageTest.cpp create mode 100644 vmime-master/tests/parser/parameterTest.cpp create mode 100644 vmime-master/tests/parser/pathTest.cpp create mode 100644 vmime-master/tests/parser/streamContentHandlerTest.cpp create mode 100644 vmime-master/tests/parser/stringContentHandlerTest.cpp create mode 100644 vmime-master/tests/parser/textTest.cpp create mode 100644 vmime-master/tests/parser/wordEncoderTest.cpp create mode 100644 vmime-master/tests/security/digest/md5Test.cpp create mode 100644 vmime-master/tests/security/digest/sha1Test.cpp create mode 100644 vmime-master/tests/testRunner.cpp create mode 100644 vmime-master/tests/testUtils.cpp create mode 100644 vmime-master/tests/testUtils.hpp create mode 100644 vmime-master/tests/utility/datetimeUtilsTest.cpp create mode 100644 vmime-master/tests/utility/encoder/b64EncoderTest.cpp create mode 100644 vmime-master/tests/utility/encoder/encoderFactoryTest.cpp create mode 100644 vmime-master/tests/utility/encoder/encoderTestUtils.hpp create mode 100644 vmime-master/tests/utility/encoder/qpEncoderTest.cpp create mode 100644 vmime-master/tests/utility/filteredStreamTest.cpp create mode 100644 vmime-master/tests/utility/outputStreamByteArrayAdapterTest.cpp create mode 100644 vmime-master/tests/utility/outputStreamSocketAdapterTest.cpp create mode 100644 vmime-master/tests/utility/outputStreamStringAdapterTest.cpp create mode 100644 vmime-master/tests/utility/parserInputStreamAdapterTest.cpp create mode 100644 vmime-master/tests/utility/pathTest.cpp create mode 100644 vmime-master/tests/utility/seekableInputStreamRegionAdapterTest.cpp create mode 100644 vmime-master/tests/utility/stringUtilsTest.cpp create mode 100644 vmime-master/tests/utility/urlTest.cpp (limited to 'vmime-master/tests') 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 +// +// 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 hdr = vmime::make_shared (); + + 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 hdr = vmime::make_shared (); + + 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 hdr1 = vmime::make_shared (); + + hdr1->getField("Importance")->setValue(ImportanceValue); + VASSERT_EQ("1", i1, vmime::misc::importanceHelper::getImportanceHeader(hdr1)); + + vmime::shared_ptr hdr2 = vmime::make_shared (); + + 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 +// +// 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 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 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 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 +// +// 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 cmd = IMAPCommand::createCommand("MY_COMMAND"); + + VASSERT_NOT_NULL("Not null", cmd); + VASSERT_EQ("Text", "MY_COMMAND", cmd->getText()); + } + + void testCreateCommandParams() { + + vmime::shared_ptr 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 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 cmd = IMAPCommand::AUTHENTICATE("saslmechanism"); + + VASSERT_NOT_NULL("Not null", cmd); + VASSERT_EQ("Text", "AUTHENTICATE saslmechanism", cmd->getText()); + } + + void testAUTHENTICATE_InitialResponse() { + + vmime::shared_ptr 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 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 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 params; + params.push_back("param-1"); + params.push_back("param-2"); + + + vmime::shared_ptr cmdRO = IMAPCommand::SELECT( + /* readOnly */ true, "mailbox-name", std::vector () + ); + + VASSERT_NOT_NULL("Not null", cmdRO); + VASSERT_EQ("Text", "EXAMINE mailbox-name", cmdRO->getText()); + + vmime::shared_ptr cmdROQuote = IMAPCommand::SELECT( + /* readOnly */ true, "mailbox name", std::vector () + ); + + VASSERT_NOT_NULL("Not null", cmdROQuote); + VASSERT_EQ("Text", "EXAMINE \"mailbox name\"", cmdROQuote->getText()); + + + vmime::shared_ptr cmdRW = IMAPCommand::SELECT( + /* readOnly */ false, "mailbox-name", std::vector () + ); + + VASSERT_NOT_NULL("Not null", cmdRW); + VASSERT_EQ("Text", "SELECT mailbox-name", cmdRW->getText()); + + vmime::shared_ptr 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 cmdRWQuote = IMAPCommand::SELECT( + /* readOnly */ false, "mailbox name", std::vector () + ); + + VASSERT_NOT_NULL("Not null", cmdRWQuote); + VASSERT_EQ("Text", "SELECT \"mailbox name\"", cmdRWQuote->getText()); + } + + void testSTATUS() { + + std::vector attribs; + attribs.push_back("attrib-1"); + attribs.push_back("attrib-2"); + + + vmime::shared_ptr 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 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 params; + params.push_back("param-1"); + params.push_back("param-2"); + + + vmime::shared_ptr 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 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 cmdNoParam = + IMAPCommand::CREATE("mailbox-name", std::vector ()); + + VASSERT_NOT_NULL("Not null", cmdNoParam); + VASSERT_EQ("Text", "CREATE mailbox-name", cmdNoParam->getText()); + } + + void testDELETE() { + + vmime::shared_ptr cmd = + IMAPCommand::DELETE("mailbox-name"); + + VASSERT_NOT_NULL("Not null", cmd); + VASSERT_EQ("Text", "DELETE mailbox-name", cmd->getText()); + + + vmime::shared_ptr cmdQuote = + IMAPCommand::DELETE("mailbox name"); + + VASSERT_NOT_NULL("Not null", cmdQuote); + VASSERT_EQ("Text", "DELETE \"mailbox name\"", cmdQuote->getText()); + } + + void testRENAME() { + + vmime::shared_ptr 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 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 params; + params.push_back("param-1"); + params.push_back("param-2"); + + + vmime::shared_ptr 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 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 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 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 flags; + flags.push_back("flag-1"); + flags.push_back("flag-2"); + + + vmime::shared_ptr 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 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 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 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 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 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 flags; + flags.push_back("flag-1"); + flags.push_back("flag-2"); + + + vmime::shared_ptr 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 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 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 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 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 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 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 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 searchKeys; + searchKeys.push_back("search-key-1"); + searchKeys.push_back("search-key-2"); + + vmime::shared_ptr 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 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 cmd = IMAPCommand::STARTTLS(); + + VASSERT_NOT_NULL("Not null", cmd); + VASSERT_EQ("Text", "STARTTLS", cmd->getText()); + } + + void testCAPABILITY() { + + vmime::shared_ptr cmd = IMAPCommand::CAPABILITY(); + + VASSERT_NOT_NULL("Not null", cmd); + VASSERT_EQ("Text", "CAPABILITY", cmd->getText()); + } + + void testNOOP() { + + vmime::shared_ptr cmd = IMAPCommand::NOOP(); + + VASSERT_NOT_NULL("Not null", cmd); + VASSERT_EQ("Text", "NOOP", cmd->getText()); + } + + void testEXPUNGE() { + + vmime::shared_ptr cmd = IMAPCommand::EXPUNGE(); + + VASSERT_NOT_NULL("Not null", cmd); + VASSERT_EQ("Text", "EXPUNGE", cmd->getText()); + } + + void testCLOSE() { + + vmime::shared_ptr cmd = IMAPCommand::CLOSE(); + + VASSERT_NOT_NULL("Not null", cmd); + VASSERT_EQ("Text", "CLOSE", cmd->getText()); + } + + void testLOGOUT() { + + vmime::shared_ptr cmd = IMAPCommand::LOGOUT(); + + VASSERT_NOT_NULL("Not null", cmd); + VASSERT_EQ("Text", "LOGOUT", cmd->getText()); + } + + void testSend() { + + vmime::shared_ptr cmd = + IMAPCommand::createCommand("MY_COMMAND param1 param2"); + + vmime::shared_ptr sess = vmime::net::session::create(); + + vmime::shared_ptr auth = + vmime::make_shared (); + + vmime::shared_ptr store = + vmime::make_shared (sess, auth, /* secured */ false); + + vmime::shared_ptr conn = + vmime::make_shared (store, auth); + + vmime::shared_ptr sok = vmime::make_shared (); + 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 +// +// 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 (); + socket->localSend(resp); + + auto parser = vmime::make_shared (); + auto tag = vmime::make_shared (); + + parser->setSocket(socket); + parser->setTimeoutHandler(vmime::make_shared ()); + parser->setStrict(true); + + VASSERT_THROW("strict mode", parser->readResponse(*tag), vmime::exceptions::invalid_response); + } + + // Non-strict mode + { + auto socket = vmime::make_shared (); + socket->localSend(resp); + + auto parser = vmime::make_shared (); + auto tag = vmime::make_shared (); + + parser->setSocket(socket); + parser->setTimeoutHandler(vmime::make_shared ()); + 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 socket = vmime::make_shared (); + vmime::shared_ptr toh = vmime::make_shared (); + + vmime::shared_ptr tag = + vmime::make_shared (); + + socket->localSend("+\r\n"); + + vmime::shared_ptr parser = + vmime::make_shared (); + + 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 (); + socket->localSend(resp); + + auto parser = vmime::make_shared (); + auto tag = vmime::make_shared (); + + parser->setSocket(socket); + parser->setTimeoutHandler(vmime::make_shared ()); + parser->setStrict(true); + + VASSERT_THROW("strict mode", parser->readResponse(*tag), vmime::exceptions::invalid_response); + } + + // Non-strict mode + { + auto socket = vmime::make_shared (); + socket->localSend(resp); + + auto parser = vmime::make_shared (); + auto tag = vmime::make_shared (); + + parser->setSocket(socket); + parser->setTimeoutHandler(vmime::make_shared ()); + 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 socket = vmime::make_shared (); + vmime::shared_ptr toh = vmime::make_shared (); + + vmime::shared_ptr tag = + vmime::make_shared (); + + 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 parser = + vmime::make_shared (); + + 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 (); + socket->localSend(resp); + + auto parser = vmime::make_shared (); + auto tag = vmime::make_shared (); + + parser->setSocket(socket); + parser->setTimeoutHandler(vmime::make_shared ()); + parser->setStrict(true); + + VASSERT_THROW("strict mode", parser->readResponse(*tag), vmime::exceptions::invalid_response); + } + + // Non-strict mode + { + auto socket = vmime::make_shared (); + socket->localSend(resp); + + auto parser = vmime::make_shared (); + auto tag = vmime::make_shared (); + + parser->setSocket(socket); + parser->setTimeoutHandler(vmime::make_shared ()); + 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 (); + socket->localSend(resp); + + auto parser = vmime::make_shared (); + auto tag = vmime::make_shared (); + + parser->setSocket(socket); + parser->setTimeoutHandler(vmime::make_shared ()); + parser->setStrict(true); + + VASSERT_THROW("strict mode", parser->readResponse(*tag), vmime::exceptions::invalid_response); + } + + // Non-strict mode + { + auto socket = vmime::make_shared (); + socket->localSend(resp); + + auto parser = vmime::make_shared (); + auto tag = vmime::make_shared (); + + parser->setSocket(socket); + parser->setTimeoutHandler(vmime::make_shared ()); + 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 socket = vmime::make_shared (); + vmime::shared_ptr toh = vmime::make_shared (); + + 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 parser = + vmime::make_shared (); + + parser->setSocket(socket); + parser->setTimeoutHandler(toh); + + // Test response a001 + vmime::scoped_ptr 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 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 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 (); + auto toh = vmime::make_shared (); + + auto tag = vmime::make_shared (); + + socket->localSend(resp); + + auto parser = vmime::make_shared (); + + 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 (); + auto toh = vmime::make_shared (); + + auto tag = vmime::make_shared (); + + socket->localSend(resp); + + auto parser = vmime::make_shared (); + + 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 +// +// 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 tag = + vmime::make_shared (); + + VASSERT_EQ("init", "a001", static_cast (*tag)); + } + + void testIncrement() { + + vmime::shared_ptr tag = + vmime::make_shared (); + + (*tag)++; + VASSERT_EQ("init", "a002", static_cast (*tag)); + + (*tag)++; + VASSERT_EQ("init", "a003", static_cast (*tag)); + + (*tag)++; + VASSERT_EQ("init", "a004", static_cast (*tag)); + } + + void testReset() { + + vmime::shared_ptr tag = + vmime::make_shared (); + + for (int i = tag->number() ; i < tag->maximumNumber() ; ++i) { + (*tag)++; + } + + VASSERT_EQ("last", "Z999", static_cast (*tag)); + + (*tag)++; + + VASSERT_EQ("reset", "a001", static_cast (*tag)); + } + + void testNumber() { + + vmime::shared_ptr tag = + vmime::make_shared (); + + 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 +// +// 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 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 cnt; + vmime::net::messageSet msgs = vmime::net::messageSet::byNumber(42); + + // SIZE + { + vmime::net::fetchAttributes attribs = vmime::net::fetchAttributes::SIZE; + + vmime::shared_ptr 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 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 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 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 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 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 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 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 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 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 +// +// 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: \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 store = + vmime::dynamicCast (createAndConnectStore()); + + VASSERT_EQ("*", "kmail", store->getFormat()->getName()); + + destroyMaildir(); + } + + void testDetectFormat_Courier() { + + createMaildir(TEST_MAILDIR_COURIER, TEST_MAILDIRFILES_COURIER); + + vmime::shared_ptr store = + vmime::dynamicCast (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 store = createAndConnectStore(); + vmime::shared_ptr rootFolder = store->getRootFolder(); + + // Get root folders, not recursive + const std::vector > + 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 store = createAndConnectStore(); + vmime::shared_ptr rootFolder = store->getRootFolder(); + + // Get all folders, recursive + const std::vector > + 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 store = createAndConnectStore(); + vmime::shared_ptr rootFolder = store->getRootFolder(); + + vmime::shared_ptr 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 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 store = createAndConnectStore(); + vmime::shared_ptr rootFolder = store->getRootFolder(); + + // Rename "Folder/SubFolder" to "Folder/foo" + vmime::shared_ptr folder = + store->getFolder(fpath() / "Folder" / "SubFolder"); + + folder->rename(fpath() / "Folder" / "foo"); + + // Ensure folder and its subfolders have been renamed + const std::vector > + 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 store = createAndConnectStore(); + vmime::shared_ptr rootFolder = store->getRootFolder(); + + // Destroy "Folder/SubFolder" (total: 3 folders) + vmime::shared_ptr folder = + store->getFolder(fpath() / "Folder" / "SubFolder"); + + folder->destroy(); + + // Ensure folder and its subfolders have been deleted and other folders still exist + const std::vector > + 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 store = createAndConnectStore(); + vmime::shared_ptr 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 store = createAndConnectStore(); + vmime::shared_ptr 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 createAndConnectStore() { + + vmime::shared_ptr session = vmime::net::session::create(); + + vmime::shared_ptr store = + session->getStore(getStoreURL()); + + store->connect(); + + return store; + } + + const vmime::shared_ptr findFolder( + const std::vector >& 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 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 fsf = + vmime::platform::getHandler()->getFileSystemFactory(); + + vmime::shared_ptr rootDir = fsf->create(m_tempPath); + rootDir->createDirectory(false); + + for (vmime::string const* dir = dirs ; *dir != "*" ; ++dir) { + + vmime::shared_ptr 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 ffile = fsf->create(m_tempPath / fsf->stringToPath(*file)); + ffile->createFile(); + + vmime::shared_ptr fileWriter = ffile->getFileWriter(); + vmime::shared_ptr os = fileWriter->getOutputStream(); + + os->write(contents.data(), contents.length()); + os->flush(); + + fileWriter = vmime::null; + } + + } + + void destroyMaildir() { + + vmime::shared_ptr fsf = + vmime::platform::getHandler()->getFileSystemFactory(); + + recursiveDelete(fsf->create(m_tempPath)); + } + + void recursiveDelete(vmime::shared_ptr dir) { + + if (!dir->exists() || !dir->isDirectory()) { + return; + } + + vmime::shared_ptr files = dir->getFiles(); + + // First, delete files and subdirectories in this directory + while (files->hasMoreElements()) { + + vmime::shared_ptr 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 +// +// 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 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 +// +// 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 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 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 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 +// +// 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 cmd = POP3Command::createCommand("MY_COMMAND"); + + VASSERT_NOT_NULL("Not null", cmd); + VASSERT_EQ("Text", "MY_COMMAND", cmd->getText()); + } + + void testCreateCommandParams() { + + vmime::shared_ptr 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 cmd = POP3Command::CAPA(); + + VASSERT_NOT_NULL("Not null", cmd); + VASSERT_EQ("Text", "CAPA", cmd->getText()); + } + + void testNOOP() { + + vmime::shared_ptr cmd = POP3Command::NOOP(); + + VASSERT_NOT_NULL("Not null", cmd); + VASSERT_EQ("Text", "NOOP", cmd->getText()); + } + + void testAUTH() { + + vmime::shared_ptr cmd = POP3Command::AUTH("saslmechanism"); + + VASSERT_NOT_NULL("Not null", cmd); + VASSERT_EQ("Text", "AUTH saslmechanism", cmd->getText()); + } + + void testAUTH_InitialResponse() { + + vmime::shared_ptr 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 cmd = POP3Command::STLS(); + + VASSERT_NOT_NULL("Not null", cmd); + VASSERT_EQ("Text", "STLS", cmd->getText()); + } + + void testAPOP() { + + vmime::shared_ptr cmd = POP3Command::APOP("user", "digest"); + + VASSERT_NOT_NULL("Not null", cmd); + VASSERT_EQ("Text", "APOP user digest", cmd->getText()); + } + + void testUSER() { + + vmime::shared_ptr cmd = POP3Command::USER("user"); + + VASSERT_NOT_NULL("Not null", cmd); + VASSERT_EQ("Text", "USER user", cmd->getText()); + } + + void testPASS() { + + vmime::shared_ptr cmd = POP3Command::PASS("pass"); + + VASSERT_NOT_NULL("Not null", cmd); + VASSERT_EQ("Text", "PASS pass", cmd->getText()); + } + + void testSTAT() { + + vmime::shared_ptr cmd = POP3Command::STAT(); + + VASSERT_NOT_NULL("Not null", cmd); + VASSERT_EQ("Text", "STAT", cmd->getText()); + } + + void testLIST() { + + vmime::shared_ptr cmd = POP3Command::LIST(); + + VASSERT_NOT_NULL("Not null", cmd); + VASSERT_EQ("Text", "LIST", cmd->getText()); + } + + void testLISTMessage() { + + vmime::shared_ptr cmd = POP3Command::LIST(42); + + VASSERT_NOT_NULL("Not null", cmd); + VASSERT_EQ("Text", "LIST 42", cmd->getText()); + } + + void testUIDL() { + + vmime::shared_ptr cmd = POP3Command::UIDL(); + + VASSERT_NOT_NULL("Not null", cmd); + VASSERT_EQ("Text", "UIDL", cmd->getText()); + } + + void testUIDLMessage() { + + vmime::shared_ptr cmd = POP3Command::UIDL(42); + + VASSERT_NOT_NULL("Not null", cmd); + VASSERT_EQ("Text", "UIDL 42", cmd->getText()); + } + + void testDELE() { + + vmime::shared_ptr cmd = POP3Command::DELE(42); + + VASSERT_NOT_NULL("Not null", cmd); + VASSERT_EQ("Text", "DELE 42", cmd->getText()); + } + + void testRETR() { + + vmime::shared_ptr cmd = POP3Command::RETR(42); + + VASSERT_NOT_NULL("Not null", cmd); + VASSERT_EQ("Text", "RETR 42", cmd->getText()); + } + + void testTOP() { + + vmime::shared_ptr cmd = POP3Command::TOP(42, 567); + + VASSERT_NOT_NULL("Not null", cmd); + VASSERT_EQ("Text", "TOP 42 567", cmd->getText()); + } + + void testRSET() { + + vmime::shared_ptr cmd = POP3Command::RSET(); + + VASSERT_NOT_NULL("Not null", cmd); + VASSERT_EQ("Text", "RSET", cmd->getText()); + } + + void testQUIT() { + + vmime::shared_ptr cmd = POP3Command::QUIT(); + + VASSERT_NOT_NULL("Not null", cmd); + VASSERT_EQ("Text", "QUIT", cmd->getText()); + } + + void testWriteToSocket() { + + vmime::shared_ptr cmd = POP3Command::createCommand("MY_COMMAND param1 param2"); + + vmime::shared_ptr sok = vmime::make_shared (); + + vmime::shared_ptr conn = + vmime::make_shared ( + vmime::dynamicCast (sok), + vmime::shared_ptr () + ); + + 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 +// +// 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 socket = vmime::make_shared (); + vmime::shared_ptr toh = vmime::make_shared (); + + vmime::shared_ptr conn = + vmime::make_shared ( + vmime::dynamicCast (socket), toh + ); + + socket->localSend("+OK Response Text\r\n"); + + vmime::shared_ptr 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 socket = vmime::make_shared (); + vmime::shared_ptr toh = vmime::make_shared (); + + vmime::shared_ptr conn = + vmime::make_shared ( + vmime::dynamicCast (socket), toh + ); + + socket->localSend("-ERR Response Text\r\n"); + + vmime::shared_ptr 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 socket = vmime::make_shared (); + vmime::shared_ptr toh = vmime::make_shared (); + + vmime::shared_ptr conn = + vmime::make_shared ( + vmime::dynamicCast (socket), toh + ); + + socket->localSend("+ challenge_string\r\n"); + + vmime::shared_ptr 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 socket = vmime::make_shared (); + vmime::shared_ptr toh = vmime::make_shared (); + + vmime::shared_ptr conn = vmime::make_shared + (vmime::dynamicCast (socket), toh); + + socket->localSend("Invalid Response Text\r\n"); + + vmime::shared_ptr 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 socket = vmime::make_shared (); + vmime::shared_ptr toh = vmime::make_shared (); + + vmime::shared_ptr conn = + vmime::make_shared ( + vmime::dynamicCast (socket), toh + ); + + socket->localSend("+OK Response terminated by LF\n"); + + vmime::shared_ptr 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 socket = vmime::make_shared (); + vmime::shared_ptr toh = vmime::make_shared (); + + vmime::shared_ptr conn = + vmime::make_shared ( + vmime::dynamicCast (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 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 socket = vmime::make_shared (); + vmime::shared_ptr toh = vmime::make_shared (); + + vmime::shared_ptr conn = + vmime::make_shared ( + vmime::dynamicCast (socket), toh + ); + + socket->localSend("+OK Response Text\n"); + socket->localSend("Line 1\n"); + socket->localSend("Line 2\n"); + socket->localSend(".\n"); + + vmime::shared_ptr 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 socket = vmime::make_shared (); + vmime::shared_ptr toh = vmime::make_shared (); + + vmime::shared_ptr conn = + vmime::make_shared ( + vmime::dynamicCast (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 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 +// +// 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 sess = vmime::net::session::create(); + + // POP3 + vmime::utility::url url("pop3://pop3.vmime.org"); + vmime::shared_ptr 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 store2 = sess->getStore(url2); + + VASSERT_TRUE("pop3s", typeid(*store2) == typeid(vmime::net::pop3::POP3SStore)); + } + + void testConnectToInvalidServer() { + + vmime::shared_ptr sess = vmime::net::session::create(); + + vmime::utility::url url("pop3://invalid-pop3-server"); + vmime::shared_ptr 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 +// +// 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 ()) { + + } +}; + + +class POP3ConnectionTest : public vmime::net::pop3::POP3Connection { + +public: + + POP3ConnectionTest( + vmime::shared_ptr socket, + vmime::shared_ptr timeoutHandler + ) + : POP3Connection(vmime::make_shared (), + vmime::shared_ptr ()), + m_socket(socket), + m_timeoutHandler(timeoutHandler) { + + } + + vmime::shared_ptr getSocket() { + + return m_socket; + } + + vmime::shared_ptr getTimeoutHandler() { + + return m_timeoutHandler; + } + +private: + + vmime::shared_ptr m_socket; + vmime::shared_ptr 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 +// +// 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 socket = vmime::make_shared (); + vmime::shared_ptr toh = vmime::make_shared (); + + vmime::shared_ptr conn = + vmime::make_shared ( + vmime::dynamicCast (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 resp = + POP3Response::readMultilineResponse(conn); + + std::map 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 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 +// +// 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 cset = SMTPCommandSet::create(/* pipelining */ false); + + VASSERT_NOT_NULL("Not null", cset); + VASSERT_FALSE("Finished", cset->isFinished()); + } + + void testCreatePipeline() { + + vmime::shared_ptr cset = SMTPCommandSet::create(/* pipelining */ true); + + VASSERT_NOT_NULL("Not null", cset); + VASSERT_FALSE("Finished", cset->isFinished()); + } + + void testAddCommand() { + + vmime::shared_ptr 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 tracer; + vmime::shared_ptr sok = vmime::make_shared (); + + 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 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 tracer; + vmime::shared_ptr sok = vmime::make_shared (); + 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 cset = SMTPCommandSet::create(/* pipelining */ false); + + cset->addCommand(SMTPCommand::createCommand("MY_COMMAND1")); + cset->addCommand(SMTPCommand::createCommand("MY_COMMAND2")); + + vmime::shared_ptr tracer; + vmime::shared_ptr sok = vmime::make_shared (); + 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 cset = SMTPCommandSet::create(/* pipelining */ true); + + cset->addCommand(SMTPCommand::createCommand("MY_COMMAND1")); + cset->addCommand(SMTPCommand::createCommand("MY_COMMAND2")); + + vmime::shared_ptr tracer; + vmime::shared_ptr sok = vmime::make_shared (); + 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 cset = SMTPCommandSet::create(/* pipelining */ false); + + cset->addCommand(SMTPCommand::createCommand("MY_COMMAND1")); + cset->addCommand(SMTPCommand::createCommand("MY_COMMAND2")); + + vmime::shared_ptr tracer; + vmime::shared_ptr sok = vmime::make_shared (); + + 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 cset = SMTPCommandSet::create(/* pipelining */ true); + + cset->addCommand(SMTPCommand::createCommand("MY_COMMAND1")); + cset->addCommand(SMTPCommand::createCommand("MY_COMMAND2")); + + vmime::shared_ptr tracer; + vmime::shared_ptr sok = vmime::make_shared (); + + 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 +// +// 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 cmd = SMTPCommand::createCommand("MY_COMMAND"); + + VASSERT_NOT_NULL("Not null", cmd); + VASSERT_EQ("Text", "MY_COMMAND", cmd->getText()); + } + + void testCreateCommandParams() { + + vmime::shared_ptr 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 cmd = SMTPCommand::HELO("hostname"); + + VASSERT_NOT_NULL("Not null", cmd); + VASSERT_EQ("Text", "HELO hostname", cmd->getText()); + } + + void testEHLO() { + + vmime::shared_ptr cmd = SMTPCommand::EHLO("hostname"); + + VASSERT_NOT_NULL("Not null", cmd); + VASSERT_EQ("Text", "EHLO hostname", cmd->getText()); + } + + void testAUTH() { + + vmime::shared_ptr cmd = SMTPCommand::AUTH("saslmechanism"); + + VASSERT_NOT_NULL("Not null", cmd); + VASSERT_EQ("Text", "AUTH saslmechanism", cmd->getText()); + } + + void testAUTH_InitialResponse() { + + vmime::shared_ptr 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 cmd = SMTPCommand::STARTTLS(); + + VASSERT_NOT_NULL("Not null", cmd); + VASSERT_EQ("Text", "STARTTLS", cmd->getText()); + } + + void testMAIL() { + + vmime::shared_ptr cmd = SMTPCommand::MAIL(vmime::mailbox("me@vmime.org"), false, "FULL", "dsn-unique-id"); + + VASSERT_NOT_NULL("Not null", cmd); + VASSERT_EQ("Text", "MAIL FROM: RET=FULL ENVID=", cmd->getText()); + } + + void testMAIL_Encoded() { + + vmime::shared_ptr cmd = SMTPCommand::MAIL( + vmime::mailbox(vmime::emailAddress("mailtest", "例え.テスト")), false, "FULL", "dsn-unique-id" + ); + + VASSERT_NOT_NULL("Not null", cmd); + VASSERT_EQ("Text", "MAIL FROM: RET=FULL ENVID=", cmd->getText()); + } + + void testMAIL_UTF8() { + + vmime::shared_ptr cmd = SMTPCommand::MAIL( + vmime::mailbox(vmime::emailAddress("mailtest", "例え.テスト")), true, "FULL", "dsn-unique-id" + ); + + VASSERT_NOT_NULL("Not null", cmd); + VASSERT_EQ("Text", "MAIL FROM: RET=FULL ENVID= SMTPUTF8", cmd->getText()); + } + + void testMAIL_SIZE() { + + vmime::shared_ptr 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: RET=FULL ENVID= SIZE=123456789", cmd->getText()); + } + + void testMAIL_SIZE_UTF8() { + + vmime::shared_ptr 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: RET=FULL ENVID= SMTPUTF8 SIZE=123456789", cmd->getText()); + } + + void testRCPT() { + + vmime::shared_ptr cmd = + SMTPCommand::RCPT(vmime::mailbox("someone@vmime.org"), false, "NEVER"); + + VASSERT_NOT_NULL("Not null", cmd); + VASSERT_EQ("Text", "RCPT TO: NOTIFY=NEVER", cmd->getText()); + } + + void testRCPT_Encoded() { + + vmime::shared_ptr cmd = SMTPCommand::RCPT( + vmime::mailbox(vmime::emailAddress("mailtest", "例え.テスト")), false, "NEVER" + ); + + VASSERT_NOT_NULL("Not null", cmd); + VASSERT_EQ("Text", "RCPT TO: NOTIFY=NEVER", cmd->getText()); + } + + void testRCPT_UTF8() { + + vmime::shared_ptr cmd = SMTPCommand::RCPT( + vmime::mailbox(vmime::emailAddress("mailtest", "例え.テスト")), true, "NEVER" + ); + + VASSERT_NOT_NULL("Not null", cmd); + VASSERT_EQ("Text", "RCPT TO: NOTIFY=NEVER", cmd->getText()); + } + + void testRSET() { + + vmime::shared_ptr cmd = SMTPCommand::RSET(); + + VASSERT_NOT_NULL("Not null", cmd); + VASSERT_EQ("Text", "RSET", cmd->getText()); + } + + void testDATA() { + + vmime::shared_ptr cmd = SMTPCommand::DATA(); + + VASSERT_NOT_NULL("Not null", cmd); + VASSERT_EQ("Text", "DATA", cmd->getText()); + } + + void testBDAT() { + + vmime::shared_ptr cmd1 = SMTPCommand::BDAT(12345, false); + + VASSERT_NOT_NULL("Not null", cmd1); + VASSERT_EQ("Text", "BDAT 12345", cmd1->getText()); + + vmime::shared_ptr cmd2 = SMTPCommand::BDAT(67890, true); + + VASSERT_NOT_NULL("Not null", cmd2); + VASSERT_EQ("Text", "BDAT 67890 LAST", cmd2->getText()); + } + + void testNOOP() { + + vmime::shared_ptr cmd = SMTPCommand::NOOP(); + + VASSERT_NOT_NULL("Not null", cmd); + VASSERT_EQ("Text", "NOOP", cmd->getText()); + } + + void testQUIT() { + + vmime::shared_ptr cmd = SMTPCommand::QUIT(); + + VASSERT_NOT_NULL("Not null", cmd); + VASSERT_EQ("Text", "QUIT", cmd->getText()); + } + + void testWriteToSocket() { + + vmime::shared_ptr cmd = SMTPCommand::createCommand("MY_COMMAND param1 param2"); + + vmime::shared_ptr tracer; + vmime::shared_ptr sok = vmime::make_shared (); + + 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 +// +// 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 tracer; + vmime::shared_ptr socket = vmime::make_shared (); + vmime::shared_ptr toh = vmime::make_shared (); + + socket->localSend("123 Response Text\r\n"); + + vmime::net::smtp::SMTPResponse::state responseState; + + vmime::shared_ptr 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 tracer; + vmime::shared_ptr socket = vmime::make_shared (); + vmime::shared_ptr toh = vmime::make_shared (); + + socket->localSend("123 Response Text\n"); + + vmime::net::smtp::SMTPResponse::state responseState; + + vmime::shared_ptr 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 tracer; + vmime::shared_ptr socket = vmime::make_shared (); + vmime::shared_ptr toh = vmime::make_shared (); + + socket->localSend( + "123-Response\r\n" + "123 Text\r\n" + ); + + vmime::net::smtp::SMTPResponse::state responseState; + + vmime::shared_ptr 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 tracer; + vmime::shared_ptr socket = vmime::make_shared (); + vmime::shared_ptr toh = vmime::make_shared (); + + socket->localSend( + "123-Response\r\n" + "456 Text\r\n" + ); + + vmime::net::smtp::SMTPResponse::state responseState; + + vmime::shared_ptr 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 tracer; + vmime::shared_ptr socket = vmime::make_shared (); + vmime::shared_ptr toh = vmime::make_shared (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 tracer; + vmime::shared_ptr socket = vmime::make_shared (); + vmime::shared_ptr toh = vmime::make_shared (1); + + socket->localSend( + "250\r\n" + ); + + vmime::net::smtp::SMTPResponse::state responseState; + + vmime::shared_ptr 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 tracer; + vmime::shared_ptr socket = vmime::make_shared (); + vmime::shared_ptr toh = vmime::make_shared (); + + socket->localSend("250 2.1.5 OK fu13sm4720601wic.7 - gsmtp\r\n"); + + vmime::net::smtp::SMTPResponse::state responseState; + + vmime::shared_ptr 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 tracer; + vmime::shared_ptr socket = vmime::make_shared (); + vmime::shared_ptr toh = vmime::make_shared (); + + socket->localSend("354 Go ahead fu13sm4720601wic.7 - gsmtp\r\n"); + + vmime::net::smtp::SMTPResponse::state responseState; + + vmime::shared_ptr 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 tracer; + vmime::shared_ptr socket = vmime::make_shared (); + vmime::shared_ptr toh = vmime::make_shared (); + + socket->localSend("250 4.2 xxx\r\n"); + + vmime::net::smtp::SMTPResponse::state responseState; + + vmime::shared_ptr 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 +// +// 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 sess = vmime::net::session::create(); + + vmime::utility::url url("smtp://invalid-smtp-server"); + vmime::shared_ptr store = sess->getTransport(url); + + VASSERT_THROW("connect", store->connect(), vmime::exceptions::connection_error); + } + + void testGreetingError() { + + vmime::shared_ptr session = vmime::net::session::create(); + + vmime::shared_ptr tr = + session->getTransport(vmime::utility::url("smtp://localhost")); + + tr->setSocketFactory(vmime::make_shared >()); + tr->setTimeoutHandlerFactory(vmime::make_shared ()); + + VASSERT_THROW( + "Connection", + tr->connect(), + vmime::exceptions::connection_greeting_error + ); + } + + void testMAILandRCPT() { + + vmime::shared_ptr session = vmime::net::session::create(); + + vmime::shared_ptr tr = + session->getTransport(vmime::utility::url("smtp://localhost")); + + tr->setSocketFactory(vmime::make_shared >()); + tr->setTimeoutHandlerFactory(vmime::make_shared ()); + + VASSERT_NO_THROW("Connection", tr->connect()); + + vmime::mailbox exp("expeditor@test.vmime.org"); + + vmime::mailboxList recips; + recips.appendMailbox(vmime::make_shared ("recipient1@test.vmime.org")); + recips.appendMailbox(vmime::make_shared ("recipient2@test.vmime.org")); + recips.appendMailbox(vmime::make_shared ("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 session = vmime::net::session::create(); + + vmime::shared_ptr tr = + session->getTransport(vmime::utility::url("smtp://localhost")); + + tr->setSocketFactory(vmime::make_shared >()); + tr->setTimeoutHandlerFactory(vmime::make_shared ()); + + tr->connect(); + + VASSERT( + "Test server should report it supports the CHUNKING extension!", + vmime::dynamicCast (tr)->getConnection()->hasExtension("CHUNKING") + ); + + vmime::mailbox exp("expeditor@test.vmime.org"); + + vmime::mailboxList recips; + recips.appendMailbox(vmime::make_shared ("recipient@test.vmime.org")); + + vmime::shared_ptr msg = vmime::make_shared (); + + tr->send(msg, exp, recips); + } + + void testSize_Chunking() { + + vmime::shared_ptr session = vmime::net::session::create(); + + vmime::shared_ptr tr = + session->getTransport(vmime::utility::url("smtp://localhost")); + + tr->setSocketFactory(vmime::make_shared > >()); + tr->setTimeoutHandlerFactory(vmime::make_shared ()); + + tr->connect(); + + VASSERT( + "Test server should report it supports the SIZE extension!", + vmime::dynamicCast (tr)->getConnection()->hasExtension("SIZE") + ); + + vmime::mailbox exp("expeditor@test.vmime.org"); + + vmime::mailboxList recips; + recips.appendMailbox(vmime::make_shared ("recipient@test.vmime.org")); + + vmime::shared_ptr msg = vmime::make_shared (); + + VASSERT_THROW( + "Max size limit exception", + tr->send(msg, exp, recips), + vmime::net::smtp::SMTPMessageSizeExceedsMaxLimitsException + ); + } + + void testSize_NoChunking() { + + vmime::shared_ptr session = vmime::net::session::create(); + + vmime::shared_ptr tr = + session->getTransport(vmime::utility::url("smtp://localhost")); + + tr->setSocketFactory(vmime::make_shared > >()); + tr->setTimeoutHandlerFactory(vmime::make_shared ()); + + tr->connect(); + + VASSERT( + "Test server should report it supports the SIZE extension!", + vmime::dynamicCast (tr)->getConnection()->hasExtension("SIZE") + ); + + vmime::mailbox exp("expeditor@test.vmime.org"); + + vmime::mailboxList recips; + recips.appendMailbox(vmime::make_shared ("recipient@test.vmime.org")); + + vmime::shared_ptr msg = vmime::make_shared (); + + 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 session = vmime::net::session::create(); + + vmime::shared_ptr tr = + session->getTransport(vmime::utility::url("smtp://localhost")); + + tr->setSocketFactory(vmime::make_shared > >()); + tr->setTimeoutHandlerFactory(vmime::make_shared ()); + + 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 ("recipient1@test.vmime.org")); + recips.appendMailbox(vmime::make_shared ("recipient2@test.vmime.org")); + recips.appendMailbox(vmime::make_shared ( + 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 session = vmime::net::session::create(); + + vmime::shared_ptr tr = + session->getTransport(vmime::utility::url("smtp://localhost")); + + tr->setSocketFactory(vmime::make_shared > >()); + tr->setTimeoutHandlerFactory(vmime::make_shared ()); + + VASSERT_NO_THROW("Connection", tr->connect()); + + vmime::mailbox exp("expediteur@test.vmime.org"); + + vmime::mailboxList recips; + recips.appendMailbox(vmime::make_shared ("recipient1@test.vmime.org")); + recips.appendMailbox(vmime::make_shared ("recipient2@test.vmime.org")); + recips.appendMailbox(vmime::make_shared ( + 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 session = vmime::net::session::create(); + + vmime::shared_ptr tr = + session->getTransport(vmime::utility::url("smtp://localhost")); + + tr->setSocketFactory(vmime::make_shared > >()); + tr->setTimeoutHandlerFactory(vmime::make_shared ()); + + 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 ("recipient1@test.vmime.org")); + recips.appendMailbox(vmime::make_shared ("recipient2@test.vmime.org")); + recips.appendMailbox(vmime::make_shared ( + 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 session = vmime::net::session::create(); + + vmime::shared_ptr tr = + session->getTransport(vmime::utility::url("smtp://localhost")); + + tr->setSocketFactory(vmime::make_shared > >()); + tr->setTimeoutHandlerFactory(vmime::make_shared ()); + + VASSERT_NO_THROW("Connection", tr->connect()); + + vmime::mailbox exp("expediteur@test.vmime.org"); + + vmime::mailboxList recips; + recips.appendMailbox(vmime::make_shared ("recipient1@test.vmime.org")); + recips.appendMailbox(vmime::make_shared ("recipient2@test.vmime.org")); + recips.appendMailbox(vmime::make_shared ( + 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 +// +// 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:"), 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 ::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 .\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 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 & getChunks() const { + + static std::vector 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 +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:", 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 +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 +class UTF8SMTPTestSocket : public lineBasedTestSocket { + +public: + + UTF8SMTPTestSocket() { + + if (SUPPORTS_UTF8) { + + m_rcptLines.insert("RCPT TO:"); + m_rcptLines.insert("RCPT TO:"); + m_rcptLines.insert("RCPT TO:"); + + } else { + + m_rcptLines.insert("RCPT TO:"); + m_rcptLines.insert("RCPT TO:"); + 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: SMTPUTF8") == line + || std::string("MAIL FROM: SMTPUTF8") == line + ); + + } else { + + VASSERT( + "MAIL", + std::string("MAIL FROM:") == 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 ::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 .\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 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 +// +// 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 & part) { + + vmime::shared_ptr 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 subPart = bdy->getPartAt(i); + + if (i != 0) { + res += ","; + } + + res += getStructure(subPart); + } + + return res + "]"; + } + + static const vmime::string extractBodyContents( + const vmime::shared_ptr & part + ) { + + vmime::shared_ptr 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 msg = vmime::make_shared (); + msg->parse(data); + + vmime::shared_ptr att = + vmime::make_shared ( + vmime::make_shared ("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 msg = vmime::make_shared (); + msg->parse(data); + + vmime::shared_ptr att = + vmime::make_shared ( + vmime::make_shared ("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 msg = vmime::make_shared (); + msg->parse(data); + + vmime::shared_ptr att = + vmime::make_shared ( + vmime::make_shared ("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 p = vmime::make_shared (); + 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 p = vmime::make_shared (); + 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 p = vmime::make_shared (); + 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 p = vmime::make_shared (); + 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 part = vmime::make_shared (); + part->parse(data); + + vmime::shared_ptr 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 (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 msg = vmime::make_shared (); + 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 amsg = vmime::make_shared (); + 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 attPart = msg->getBody()->getPartAt(1); + vmime::shared_ptr attCth = attPart->getBody()->getContents(); + + vmime::string attDataOut; + vmime::utility::outputStreamStringAdapter attDataOutOs(attDataOut); + + attCth->extract(attDataOutOs); + + vmime::shared_ptr amsgOut = vmime::make_shared (); + amsgOut->parse(attDataOut); + + vmime::shared_ptr hdr = amsgOut->getHeader(); + + VASSERT_EQ("3", "Attached message", hdr->Subject()->getValue ()->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 msg = vmime::make_shared (); + msg->parse(data); + + VASSERT_EQ("0", 2, msg->getBody()->getPartCount()); + + vmime::shared_ptr att = + vmime::attachmentHelper::getBodyPartAttachment(msg->getBody()->getPartAt(0)); + + VASSERT("1", att != NULL); + + vmime::shared_ptr msgAtt = + vmime::dynamicCast (att); + + VASSERT("2", msgAtt != NULL); + + vmime::shared_ptr amsg = msgAtt->getMessage(); + vmime::shared_ptr hdr = amsg->getHeader(); + + VASSERT_EQ("3", "Attached message", hdr->Subject()->getValue ()->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 +// +// 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 & 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 ("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 msg = vmime::make_shared(); + + 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 p1 = vmime::make_shared (); + p1->setText(vmime::make_shared ("Part1 is US-ASCII only.")); + + vmime::shared_ptr msg = vmime::make_shared (); + p1->generateIn(msg, msg); + + vmime::shared_ptr header1 = msg->getBody()->getPartAt(0)->getHeader(); + VASSERT_EQ("1", "7bit", header1->ContentTransferEncoding()->getValue()->generate()); + } + + void testTextUsageForQPEncoding() { + + vmime::shared_ptr part = vmime::make_shared (); + part->setText(vmime::make_shared ("Part1-line1\r\nPart1-line2\r\n\x89")); + + vmime::shared_ptr msg = vmime::make_shared (); + part->generateIn(msg, msg); + + vmime::shared_ptr body = msg->getBody()->getPartAt(0)->getBody(); + vmime::shared_ptr 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 is = + vmime::make_shared (oss.str()); + + vmime::shared_ptr msg = vmime::make_shared (); + msg->parse(is, oss.str().length()); + + vmime::shared_ptr body1 = msg->getBody()->getPartAt(0)->getBody(); + vmime::shared_ptr body1Cts = body1->getContents(); + + vmime::shared_ptr body2 = msg->getBody()->getPartAt(1)->getBody(); + vmime::shared_ptr 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 (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 (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 +// +// 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 ( + "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 ( + "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 +// +// 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 cc = + vmime::charsetConverter::create("utf-8", "iso-8859-1"); + + vmime::string output; + vmime::utility::outputStreamStringAdapter os(output); + vmime::shared_ptr 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 conv = + vmime::charsetConverter::create(vmime::charset("utf-8"), vmime::charset("iso-8859-1")); + + vmime::shared_ptr 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 conv = + vmime::charsetConverter::create(entry.fromCharset, entry.toCharset); + + vmime::shared_ptr 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 conv = + vmime::charsetConverter::create(entry.fromCharset, entry.toCharset); + + vmime::shared_ptr 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 conv = + vmime::charsetConverter::create(entry.fromCharset, entry.toCharset); + + vmime::shared_ptr 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 +// +// 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 + +#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 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 +// +// 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 +// +// 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 +// +// 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 (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 (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 (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 (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 (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 (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 (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 (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 (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 (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 +// +// 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 +#include + + +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 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 +// +// 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 +// +// 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 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 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 +// +// 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 hfactory = + vmime::headerFieldFactory::getInstance(); + + // "To" header field accepts values of type "addressList" + vmime::shared_ptr 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 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 hfield = + vmime::headerField::parseNext(ctx, buffer, 0, buffer.size()); + + vmime::shared_ptr hvalue = + hfield->getValue (); + + 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 hfield = + vmime::headerField::parseNext(ctx, buffer, 0, buffer.size()); + + vmime::shared_ptr hvalue = + hfield->getValue (); + + 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 hfield = + vmime::headerField::parseNext(ctx, buffer, 0, buffer.size()); + + vmime::shared_ptr hvalue = + hfield->getValue (); + + 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 +// +// 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 hf = vmime::headerFieldFactory::getInstance()->create("A", "a"); + hdr.appendField(hf); + + std::vector > res = hdr.getFieldList(); + + VASSERT_EQ("Count", static_cast (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 hf = vmime::headerFieldFactory::getInstance()->create("B", "b"); + hdr.appendField(hf); + + std::vector > res = hdr.getFieldList(); + + VASSERT_EQ("Count", static_cast (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 hf = vmime::headerFieldFactory::getInstance()->create("B", "b"); + hdr.insertFieldBefore(hdr.getField("C"), hf); + + std::vector > res = hdr.getFieldList(); + + VASSERT_EQ("Count", static_cast (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 hf = vmime::headerFieldFactory::getInstance()->create("B", "b"); + hdr.insertFieldBefore(1, hf); + + std::vector > res = hdr.getFieldList(); + + VASSERT_EQ("Count", static_cast (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 hf = vmime::headerFieldFactory::getInstance()->create("B", "b"); + hdr.insertFieldAfter(hdr.getField("A"), hf); + + std::vector > res = hdr.getFieldList(); + + VASSERT_EQ("Count", static_cast (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 hf = vmime::headerFieldFactory::getInstance()->create("B", "b"); + hdr.insertFieldAfter(0, hf); + + std::vector > res = hdr.getFieldList(); + + VASSERT_EQ("Count", static_cast (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 hf = vmime::headerFieldFactory::getInstance()->create("Z", "z"); + hdr.replaceField(hdr.getField("B"), hf); + + std::vector > res = hdr.getFieldList(); + + VASSERT_EQ("Count", static_cast (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 > res1 = hdr1.getFieldList(); + + VASSERT_EQ("Count", static_cast (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 > res2 = hdr2.getFieldList(); + + VASSERT_EQ("Count", static_cast (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 > res1 = hdr1.getFieldList(); + VASSERT_EQ("Count", static_cast (0), res1.size()); + + std::vector > res2 = hdr2.getFieldList(); + VASSERT_EQ("Count", static_cast (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 > res1 = hdr1.getFieldList(); + VASSERT_EQ("Count", static_cast (0), res1.size()); + + std::vector > res2 = hdr2.getFieldList(); + VASSERT_EQ("Count", static_cast (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 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 > res = hdr.getFieldList(); + + VASSERT_EQ("Count", static_cast (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 > res = hdr.getFieldList(); + + VASSERT_EQ("Count", static_cast (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 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 > res = hdr.findAllFields("B"); + + VASSERT_EQ("Count", static_cast (0), res.size()); + } + + void testFindAllFields2() { + + vmime::header hdr; + hdr.parse("A: a1\nB: b1\nB: b2\nC: c1\n"); + + std::vector > res = hdr.findAllFields("B"); + + VASSERT_EQ("Count", static_cast (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 > res = hdr.findAllFields("C"); + + VASSERT_EQ("Count", static_cast (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 +// +// 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 & 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" +"\r\n" +"--LEVEL2\r\n" +"Content-Type: image/png; name=\"image.png\"\r\n" +"Content-Disposition: inline; filename=\"image.png\"\r\n" +"Content-ID: \r\n" +"\r\n" +"Image\r\n" +"--LEVEL2--\r\n" +"\r\n" +"--LEVEL1--\r\n" +""; + + vmime::shared_ptr msg = vmime::make_shared (); + 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", "", 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: \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" +"\r\n" +"\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: \r\n" +"\r\n" +"Image2\r\n" +"--LEVEL2--\r\n" +"\r\n" +"--LEVEL1--\r\n" +""; + + vmime::shared_ptr msg = vmime::make_shared (); + 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 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: \r\n" +"\r\n" +"Image1\r\n" +"--LEVEL2\r\n" +"Content-Type: text/html; charset=\"x-ch2\"\r\n" +"\r\n" +"\r\n" +"--LEVEL2--\r\n" +"\r\n" +"--LEVEL1--\r\n" +""; + + vmime::shared_ptr msg = vmime::make_shared (); + 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 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 +// +// 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 , bbb "); + + 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 , bbb "); + + VASSERT_EQ("count", 1, addrs.getAddressCount()); + VASSERT_TRUE("is group", addrs.getAddressAt(0)->isGroup()); + + vmime::shared_ptr mgrp = + vmime::dynamicCast (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 , bbb ; 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 +// +// 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:: + void testParseGroup() { + + // Groups should be extracted to multiple mailboxes in mailbox lists + vmime::mailboxList mboxList; + mboxList.parse("email1@domain1.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 +// +// 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 ", + + "[address-list: [[mailbox: name=[text: [[word: charset=us-ascii, buffer=My name]]], email=me@somewhere.com]]]", + + // Test 2 + "mailbox1 ,;,,, ,, ,,;group1:mailbox1@group1, mailbox2@group2,,\"mailbox #3\" ;, ,,,,,,,,=?iso-8859-1?q?mailbox_number_3?= , =?abc?Q?mailbox?= =?def?Q?_number_4?= ", + + "[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 ", + + "[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 + "", + + "[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\" ", + + "[address-list: [[mailbox: name=[text: [[word: charset=us-ascii, buffer=John Doe]]], email=john.doe@acme.com]]]", + + // Test 9 + "=?us-ascii?q?John?=", + + "[address-list: [[mailbox: name=[text: [[word: charset=us-ascii, buffer=John]]], email=john.doe@acme.com]]]", + + // Test 10 + "\"John\"", + + "[address-list: [[mailbox: name=[text: [[word: charset=us-ascii, buffer=John]]], email=john.doe@acme.com]]]", + + // Test 11 + "John", + + "[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 mbox = + vmime::dynamicCast (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 mbox1 = + vmime::dynamicCast (addrList.getAddressAt(0)); + vmime::shared_ptr mbox2 = + vmime::dynamicCast (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 "); + 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 "); + VASSERT_EQ("name", vmime::text("a@b.c e@f.g"), mbox.getName()); + VASSERT_EQ("email", "h@i.j", mbox.getEmail()); + + mbox.parse("Foo "); + VASSERT_EQ("name", vmime::text("Foo "); + VASSERT_EQ("name", vmime::text("Foo "), mbox.getName()); + VASSERT_EQ("email", "bar@x.com", mbox.getEmail()); + + mbox.parse("Foo Bar "); + VASSERT_EQ("name", vmime::text("Foo 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(text(word("Foo B@r", charsets::US_ASCII)), e); + VASSERT_EQ("generate", "\"Foo B@r\" ", a->generate()); + VASSERT_NEQ("generate", "=?utf-8?Q?Foo_B=40r?= ", a->generate()); + + a = make_shared(text(word("Foo B@r", charsets::UTF_8)), e); + VASSERT_EQ("generate", "=?utf-8?Q?Foo_B=40r?= ", 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 +// +// 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 +// +// 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(""); + + 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(" \r\n\t"); + + 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 ("a", "b")); + + VASSERT_EQ("1", "", s1.generate()); + + vmime::messageIdSequence s2; + s2.appendMessageId(vmime::make_shared ("a", "b")); + s2.appendMessageId(vmime::make_shared ("c", "d")); + + VASSERT_EQ("2", " ", 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 +// +// 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(""); + + 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", "", 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", "", 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 +// +// 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 msg = vmime::make_shared (); + msg->getHeader()->getField("Foo")->setValue(vmime::string("bar")); + + vmime::htmlTextPart textPart; + textPart.setPlainText( + vmime::make_shared ( + "Foo bar bazé foo foo foo" + ) + ); + textPart.setText( + vmime::make_shared ( + "Foo bar bazé 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 +// +// 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 +#include + + +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 ("param1", "value1")); + + VASSERT_EQ("1", "F: X; param1=value1", p1.generate()); + + // Value that needs quoting (1/2) + parameterizedHeaderField p2a; + p2a.appendParameter(vmime::make_shared ("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 ("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 ( + "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 ( + "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 ( + "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 ( + "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 ("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 ("p", "val(ue")->generate()); + VASSERT_EQ(" 2", "p=\"val)ue\"", vmime::make_shared ("p", "val)ue")->generate()); + VASSERT_EQ(" 3", "p=\"val("p", "valgenerate()); + VASSERT_EQ(" 4", "p=\"val>ue\"", vmime::make_shared ("p", "val>ue")->generate()); + VASSERT_EQ(" 5", "p=\"val@ue\"", vmime::make_shared ("p", "val@ue")->generate()); + VASSERT_EQ(" 6", "p=\"val,ue\"", vmime::make_shared ("p", "val,ue")->generate()); + VASSERT_EQ(" 7", "p=\"val;ue\"", vmime::make_shared ("p", "val;ue")->generate()); + VASSERT_EQ(" 8", "p=\"val:ue\"", vmime::make_shared ("p", "val:ue")->generate()); + VASSERT_EQ(" 9", "p=\"val/ue\"", vmime::make_shared ("p", "val/ue")->generate()); + VASSERT_EQ("10", "p=\"val[ue\"", vmime::make_shared ("p", "val[ue")->generate()); + VASSERT_EQ("11", "p=\"val]ue\"", vmime::make_shared ("p", "val]ue")->generate()); + VASSERT_EQ("12", "p=\"val?ue\"", vmime::make_shared ("p", "val?ue")->generate()); + VASSERT_EQ("13", "p=\"val=ue\"", vmime::make_shared ("p", "val=ue")->generate()); + VASSERT_EQ("14", "p=\"val ue\"", vmime::make_shared ("p", "val ue")->generate()); + VASSERT_EQ("15", "p=\"val\tue\"", vmime::make_shared ("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 ( + "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 +// +// 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(""); + + VASSERT_EQ("2.1", "", p2.getLocalPart()); + VASSERT_EQ("2.2", "domain", p2.getDomain()); + + vmime::path p3; + p3.parse(""); + + 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", "", 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", "", 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 +// +// 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 stream = + vmime::make_shared (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 stream = + vmime::make_shared (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 stream2 = + vmime::make_shared (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 stream = + vmime::make_shared (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 stream = + vmime::make_shared (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 stream = + vmime::make_shared (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 stream = + vmime::make_shared (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 stream = + vmime::make_shared (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 stream = + vmime::make_shared (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 +// +// 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 +// +// 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 +#include + + +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 (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 ("\xc3\x89t\xc3\xa9", "utf-8")); + txt.appendWord(vmime::make_shared ("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 ("Facture ", "utf-8")); + txt.appendWord(vmime::make_shared ("\xc3\xa0", "utf-8")); + txt.appendWord(vmime::make_shared (" envoyer ", "utf-8")); + txt.appendWord(vmime::make_shared ("\xc3\xa0", "utf-8")); + txt.appendWord(vmime::make_shared (" 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?= ", mbox.generate()); + + vmime::text txt; + txt.appendWord(vmime::make_shared ("Achim ", "us-ascii")); + txt.appendWord(vmime::make_shared ("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?= ", mbox.generate()); + + mbox.parse("=?us-ascii?Q?Achim?= =?utf-8?Q?Br=C3=A4ndt?= "); + 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 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 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 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 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?=' "; + + vmime::shared_ptr hfield = + vmime::headerField::parseNext(ctx, hfieldBuffer, 0, hfieldBuffer.size()); + + vmime::shared_ptr hvalue = + hfield->getValue (); + + 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 +// +// 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 +// +// 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 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 +// +// 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 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 +// +// 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 +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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 (tv.tv_sec - m_start.tv_sec) + + static_cast (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 m_suiteElt; + CppUnit::XmlElement* m_testElt; +}; + + + +// see testUtils.hpp + +std::vector & getTestModules() { + + static std::vector allModules; + return allModules; +} + + +void registerTestModule(const char* name_) { + + std::vector & 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 +// +// 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 +#include + + +// 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 testSocket::getTimeoutHandler() { + + return vmime::null; +} + + +void testSocket::setTracer(const vmime::shared_ptr & /* tracer */) { + +} + + +vmime::shared_ptr 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 (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 (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 (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 testTimeoutHandlerFactory::create() { + + return vmime::make_shared (); +} + + + +// 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 (&e)) { + + const vmime::exceptions::command_error& cee = + dynamic_cast (e); + + os << " command = " << cee.command() << std::endl; + os << " response = " << cee.response() << std::endl; + } + + if (dynamic_cast (&e)) { + + const vmime::exceptions::invalid_response& ir = + dynamic_cast (e); + + os << " response = " << ir.response() << std::endl; + } + + if (dynamic_cast (&e)) { + + const vmime::exceptions::connection_greeting_error& cgee = + dynamic_cast (e); + + os << " response = " << cgee.response() << std::endl; + } + + if (dynamic_cast (&e)) { + + const vmime::exceptions::authentication_error& aee = + dynamic_cast (e); + + os << " response = " << aee.response() << std::endl; + } + + if (dynamic_cast (&e)) { + + const vmime::exceptions::filesystem_exception& fse = + dynamic_cast (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 (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 +// +// 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 +#include +#include +#include +#include + + +// VMime +#include "vmime/vmime.hpp" + + +// CppUnit +#pragma GCC diagnostic ignored "-Wold-style-cast" +#include +#include +#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 (autoRegisterRegistry1);*/ \ + /*static CppUnit::AutoRegisterSuite (autoRegisterRegistry2)(VMIME_TEST_SUITE_MODULE);*/ \ + extern void registerTestModule(const char* name); \ + extern const char* getTestModuleNameFromSourceFile(const char *path); \ + template \ + struct AutoRegisterModule { \ + AutoRegisterModule() { \ + static const char* moduleName = getTestModuleNameFromSourceFile(__FILE__); \ + static CppUnit::AutoRegisterSuite (autoRegisterRegistry1); \ + static CppUnit::AutoRegisterSuite (autoRegisterRegistry2)(moduleName); \ + registerTestModule(moduleName); \ + } \ + }; \ + static AutoRegisterModule 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 + void assertEquals( + const X expected, + const Y actual, + SourceLine sourceLine, + const std::string &message + ) { + + assertEquals(static_cast (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 (addr); + + os << group; + + } else { + + const vmime::mailbox& mbox = + dynamic_cast (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 getTimeoutHandler(); + + void setTracer(const vmime::shared_ptr & tracer); + vmime::shared_ptr 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 +class testSocketFactory : public vmime::net::socketFactory { + +public: + + vmime::shared_ptr create() { + + return vmime::make_shared (); + } + + vmime::shared_ptr create( + const vmime::shared_ptr & /* th */ + ) { + + return vmime::make_shared (); + } +}; + + +class lineBasedTestSocket : public testSocket { + +public: + + void onDataReceived(); + + const vmime::string getNextLine(); + bool haveMoreLines() const; + + virtual void processCommand() = 0; + +private: + + std::vector 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 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 +// +// 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 +// +// 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 +// +// 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 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 ef = + vmime::utility::encoder::encoderFactory::getInstance(); + + ef->setDefaultEncoder(vmime::make_shared ()); + + 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 +// +// 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 getEncoder( + const vmime::string& name, + int maxLineLength = 0, + const vmime::propertySet props = vmime::propertySet() +) { + + vmime::shared_ptr 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 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 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 +// +// 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: . 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 +// +// 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 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 + 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("1", "foo\n..bar", "foo\n.bar"); + testFilteredOutputStreamHelper("2", "foo\n..bar", "foo\n", ".bar"); + testFilteredOutputStreamHelper("3", "foo\n..bar", "foo", "\n.bar"); + testFilteredOutputStreamHelper("4", "foo\n..bar", "foo", "\n", ".bar"); + testFilteredOutputStreamHelper("5", "foo\n..bar", "foo", "\n", ".", "bar"); + + testFilteredOutputStreamHelper("6", "..\nfoobar", ".\nfoobar"); + testFilteredOutputStreamHelper("7", "..\r\nfoobar", ".\r\nfoobar"); + testFilteredOutputStreamHelper("8", "..\r\nfoobar", ".\r", "\nfoobar"); + testFilteredOutputStreamHelper("9", ".foobar", ".foobar"); + testFilteredOutputStreamHelper("10", ".foobar", ".", "foobar"); + + testFilteredOutputStreamHelper("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("1", "foo\nbar", "foo\r\nbar"); + testFilteredOutputStreamHelper("2", "foo\nbar", "foo\r\n", "bar"); + testFilteredOutputStreamHelper("3", "foo\nbar", "foo\r", "\nbar"); + testFilteredOutputStreamHelper("4", "foo\nbar", "foo", "\r\nbar"); + testFilteredOutputStreamHelper("5", "foo\nbar", "foo", "\r", "\nbar"); + testFilteredOutputStreamHelper("6", "foo\nbar", "foo", "\r", "\n", "bar"); + testFilteredOutputStreamHelper("7", "foo\nba\nr", "foo\r", "\nba\r\nr"); + } + + // stopSequenceFilteredInputStream + + template + 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 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("1", "ABC\r\nDEF", "ABC\nDEF"); + testFilteredOutputStreamHelper("2", "ABC\r\nDEF", "ABC\rDEF"); + testFilteredOutputStreamHelper("3", "\r\n\r\nAB\r\n\r\nA\r\nB\r\n", "\n\nAB\n\nA\nB\n"); + testFilteredOutputStreamHelper("4", "ABCDE\r\nF", "ABCDE\nF"); + testFilteredOutputStreamHelper("5", "ABCDE\r\nF", "ABCDE\r\nF"); + testFilteredOutputStreamHelper("6", "\r\n\r\n\r\n", "\n\n\n"); + testFilteredOutputStreamHelper("7", "\r\n\r\n\r\n", "\r\r\n\n"); + testFilteredOutputStreamHelper("8", "\r\n\r\n\r\n\r\n", "\r\r\r\r"); + testFilteredOutputStreamHelper("9", "\r\n\r\n\r\n\r\n", "\n\n\n\n"); + testFilteredOutputStreamHelper("10", "\r\n\r\n\r\n", "\r\n\n\n"); + testFilteredOutputStreamHelper("11", "\r\n\r\n\r\n\r\n", "\n\n\n\r\n"); + } + + void testLFToCRLFFilteredOutputStream_Edge() { + + typedef vmime::utility::LFToCRLFFilteredOutputStream FILTER; + + testFilteredOutputStreamHelper("1", "\r\n\r\n", "\r", "\r"); + testFilteredOutputStreamHelper("2", "\r\n\r\n", "\r", "\n\r"); + testFilteredOutputStreamHelper("3", "ABC\r\n\r\n", "ABC\r", "\n\r"); + testFilteredOutputStreamHelper("4", "ABC\r\n\r\n\r\n", "ABC\r", "\n\r", "\n\n"); + testFilteredOutputStreamHelper("5", "\r\n\r\n", "\n", "\n"); + testFilteredOutputStreamHelper("6", "\r\n\r\n", "\r\n\r\n"); + testFilteredOutputStreamHelper("7", "\r\n\r\n", "\r\n\r", "\n"); + + testFilteredOutputStreamHelper("8", "A\r\nB\r\nC\r\nD", "A\rB", "\nC\r\nD"); + testFilteredOutputStreamHelper("9", "\r\nA\r\nB\r\nC\r\nD", "\rA\r", "B\nC\r\nD"); + testFilteredOutputStreamHelper("10", "\r\nA\r\nB\r\nC\r\nD", "\nA\r", "B\nC\r\nD"); + testFilteredOutputStreamHelper("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 +// +// 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 +// +// 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 socket = vmime::make_shared (); + + 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 socket = vmime::make_shared (); + + 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 socket = vmime::make_shared (); + + 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 +// +// 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 +// +// 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 iss = + vmime::make_shared (str); + + vmime::shared_ptr parser = + vmime::make_shared (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 +// +// 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 +// +// 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 createStream( + vmime::shared_ptr * underlyingStream = NULL + ) { + + vmime::string buffer("THIS IS A TEST BUFFER"); + + vmime::shared_ptr strStream = + vmime::make_shared (buffer); + + vmime::shared_ptr rgnStream = + vmime::make_shared (strStream, 10, 11); + + if (underlyingStream) { + *underlyingStream = strStream; + } + + return rgnStream; + } + + void testInitialPosition() { + + vmime::shared_ptr stream = createStream(); + + VASSERT_EQ("Pos", 0, stream->getPosition()); + VASSERT_FALSE("EOF", stream->eof()); + } + + void testSeekAndGetPosition() { + + vmime::shared_ptr 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 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 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 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 ustream; + vmime::shared_ptr 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 +// +// 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 (3), + stringUtils::countASCIIchars(str1.begin(), str1.end()) + ); + + vmime::string str2("f=?oo"); + VASSERT_EQ( + "2", + static_cast (3 + 1), + stringUtils::countASCIIchars(str2.begin(), str2.end()) + ); + + vmime::string str3("foo\x7f"); + VASSERT_EQ( + "3", + static_cast (4), + stringUtils::countASCIIchars(str3.begin(), str3.end()) + ); + + vmime::string str4("foo\x80"); + VASSERT_EQ( + "4", + static_cast (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 +// +// 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 (u1) + ); + + vmime::utility::url u2("proto", "host"); + VASSERT_EQ("2", "proto://host", static_cast (u2)); + + vmime::utility::url u3("proto", "host"); + u3.getParams()["p1"] = "v1"; + VASSERT_EQ( + "3.1", + "proto://host/?p1=v1", + static_cast (u3) + ); + u3.getParams()["p2"] = "v2"; + VASSERT_EQ( + "3.2", + "proto://host/?p1=v1&p2=v2", + static_cast (u3) + ); + + // Test special characters + u3.getParams().clear(); + u3.getParams()["&"] = "="; + VASSERT_EQ( + "3.3", + "proto://host/?%26=%3D", + static_cast (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 (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 -- cgit v1.2.3