aboutsummaryrefslogtreecommitdiff
path: root/vmime-master/tests/parser
diff options
context:
space:
mode:
Diffstat (limited to 'vmime-master/tests/parser')
-rw-r--r--vmime-master/tests/parser/attachmentHelperTest.cpp335
-rw-r--r--vmime-master/tests/parser/bodyPartTest.cpp414
-rw-r--r--vmime-master/tests/parser/bodyTest.cpp79
-rw-r--r--vmime-master/tests/parser/charsetFilteredOutputStreamTest.cpp213
-rw-r--r--vmime-master/tests/parser/charsetTest.cpp252
-rw-r--r--vmime-master/tests/parser/charsetTestSuites.hpp102
-rw-r--r--vmime-master/tests/parser/datetimeTest.cpp123
-rw-r--r--vmime-master/tests/parser/dispositionTest.cpp150
-rw-r--r--vmime-master/tests/parser/emailAddressTest.cpp281
-rw-r--r--vmime-master/tests/parser/emptyContentHandlerTest.cpp99
-rw-r--r--vmime-master/tests/parser/fileContentHandlerTest.cpp134
-rw-r--r--vmime-master/tests/parser/headerFieldTest.cpp112
-rw-r--r--vmime-master/tests/parser/headerTest.cpp375
-rw-r--r--vmime-master/tests/parser/htmlTextPartTest.cpp241
-rw-r--r--vmime-master/tests/parser/mailboxGroupTest.cpp107
-rw-r--r--vmime-master/tests/parser/mailboxListTest.cpp47
-rw-r--r--vmime-master/tests/parser/mailboxTest.cpp187
-rw-r--r--vmime-master/tests/parser/mediaTypeTest.cpp100
-rw-r--r--vmime-master/tests/parser/messageIdSequenceTest.cpp78
-rw-r--r--vmime-master/tests/parser/messageIdTest.cpp77
-rw-r--r--vmime-master/tests/parser/messageTest.cpp64
-rw-r--r--vmime-master/tests/parser/parameterTest.cpp722
-rw-r--r--vmime-master/tests/parser/pathTest.cpp102
-rw-r--r--vmime-master/tests/parser/streamContentHandlerTest.cpp194
-rw-r--r--vmime-master/tests/parser/stringContentHandlerTest.cpp165
-rw-r--r--vmime-master/tests/parser/textTest.cpp918
-rw-r--r--vmime-master/tests/parser/wordEncoderTest.cpp174
27 files changed, 5845 insertions, 0 deletions
diff --git a/vmime-master/tests/parser/attachmentHelperTest.cpp b/vmime-master/tests/parser/attachmentHelperTest.cpp
new file mode 100644
index 0000000..866f8de
--- /dev/null
+++ b/vmime-master/tests/parser/attachmentHelperTest.cpp
@@ -0,0 +1,335 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "tests/testUtils.hpp"
+
+
+VMIME_TEST_SUITE_BEGIN(attachmentHelperTest)
+
+ VMIME_TEST_LIST_BEGIN
+ VMIME_TEST(testAddAttachment1)
+ VMIME_TEST(testAddAttachment2)
+ VMIME_TEST(testAddAttachment3)
+ VMIME_TEST(testIsBodyPartAnAttachment1)
+ VMIME_TEST(testIsBodyPartAnAttachment2)
+ VMIME_TEST(testIsBodyPartAnAttachment3)
+ VMIME_TEST(testGetBodyPartAttachment)
+ VMIME_TEST(testAddAttachmentMessage1)
+ VMIME_TEST(testGetBodyPartAttachmentMessage)
+ VMIME_TEST_LIST_END
+
+
+ static const vmime::string getStructure(const vmime::shared_ptr <vmime::bodyPart>& part) {
+
+ vmime::shared_ptr <vmime::body> bdy = part->getBody();
+
+ vmime::string res = part->getBody()->getContentType().generate();
+
+ if (bdy->getPartCount() == 0) {
+ return res;
+ }
+
+ res += "[";
+
+ for (size_t i = 0 ; i < bdy->getPartCount() ; ++i) {
+
+ vmime::shared_ptr <vmime::bodyPart> subPart = bdy->getPartAt(i);
+
+ if (i != 0) {
+ res += ",";
+ }
+
+ res += getStructure(subPart);
+ }
+
+ return res + "]";
+ }
+
+ static const vmime::string extractBodyContents(
+ const vmime::shared_ptr <const vmime::bodyPart>& part
+ ) {
+
+ vmime::shared_ptr <const vmime::contentHandler> cth = part->getBody()->getContents();
+
+ vmime::string data;
+ vmime::utility::outputStreamStringAdapter os(data);
+
+ cth->extract(os);
+
+ return data;
+ }
+
+ void testAddAttachment1() {
+
+ vmime::string data =
+"Content-Type: text/plain\r\n"
+"\r\n"
+"The text\r\n"
+"";
+
+ vmime::shared_ptr <vmime::message> msg = vmime::make_shared <vmime::message>();
+ msg->parse(data);
+
+ vmime::shared_ptr <vmime::attachment> att =
+ vmime::make_shared <vmime::defaultAttachment>(
+ vmime::make_shared <vmime::stringContentHandler>("test"),
+ vmime::mediaType("image/jpeg")
+ );
+
+ vmime::attachmentHelper::addAttachment(msg, att);
+
+ VASSERT_EQ("1", "multipart/mixed[text/plain,image/jpeg]", getStructure(msg));
+ VASSERT_EQ("2", "The text\r\n", extractBodyContents(msg->getBody()->getPartAt(0)));
+ }
+
+ void testAddAttachment2() {
+
+ vmime::string data =
+"Content-Type: multipart/mixed; boundary=\"foo\"\r\n"
+"\r\n"
+"--foo\r\n"
+"Content-Type: text/plain\r\n"
+"\r\n"
+"The text\r\n"
+"--foo\r\n"
+"Content-Type: application/octet-stream\r\n"
+"\r\n"
+"Blah\r\n"
+"--foo--\r\n"
+"";
+
+ vmime::shared_ptr <vmime::message> msg = vmime::make_shared <vmime::message>();
+ msg->parse(data);
+
+ vmime::shared_ptr <vmime::attachment> att =
+ vmime::make_shared <vmime::defaultAttachment>(
+ vmime::make_shared <vmime::stringContentHandler>("test"),
+ vmime::mediaType("image/jpeg")
+ );
+
+ vmime::attachmentHelper::addAttachment(msg, att);
+
+ VASSERT_EQ("1", "multipart/mixed[text/plain,application/octet-stream,image/jpeg]", getStructure(msg));
+ VASSERT_EQ("2", "The text", extractBodyContents(msg->getBody()->getPartAt(0)));
+ VASSERT_EQ("3", "Blah", extractBodyContents(msg->getBody()->getPartAt(1)));
+ VASSERT_EQ("4", "test", extractBodyContents(msg->getBody()->getPartAt(2)));
+ }
+
+ // Initial part is encoded
+ void testAddAttachment3() {
+
+ vmime::string data =
+"Content-Type: text/plain\r\n"
+"Content-Transfer-Encoding: base64\r\n"
+"\r\n"
+"TWVzc2FnZSBib2R5";
+
+ vmime::shared_ptr <vmime::message> msg = vmime::make_shared <vmime::message>();
+ msg->parse(data);
+
+ vmime::shared_ptr <vmime::attachment> att =
+ vmime::make_shared <vmime::defaultAttachment>(
+ vmime::make_shared <vmime::stringContentHandler>("test"),
+ vmime::mediaType("image/jpeg")
+ );
+
+ vmime::attachmentHelper::addAttachment(msg, att);
+
+ VASSERT_EQ("1", "multipart/mixed[text/plain,image/jpeg]", getStructure(msg));
+ VASSERT_EQ("2", "Message body", extractBodyContents(msg->getBody()->getPartAt(0)));
+ }
+
+ // Content-Disposition: attachment
+ // No other field
+ void testIsBodyPartAnAttachment1() {
+
+ vmime::string data = "Content-Disposition: attachment\r\n\r\nFoo\r\n";
+
+ vmime::shared_ptr <vmime::bodyPart> p = vmime::make_shared <vmime::bodyPart>();
+ p->parse(data);
+
+ VASSERT_EQ("1", true, vmime::attachmentHelper::isBodyPartAnAttachment(p));
+ }
+
+ // No Content-Disposition field
+ // Content-Type: multipart/* or text/*
+ void testIsBodyPartAnAttachment2() {
+
+ vmime::string data = "Content-Type: multipart/*\r\n\r\nFoo\r\n";
+
+ vmime::shared_ptr <vmime::bodyPart> p = vmime::make_shared <vmime::bodyPart>();
+ p->parse(data);
+
+ VASSERT_EQ("1", false, vmime::attachmentHelper::isBodyPartAnAttachment(p));
+
+ data = "Content-Type: text/*\r\n\r\nFoo\r\n";
+
+ p->parse(data);
+
+ VASSERT_EQ("2", false, vmime::attachmentHelper::isBodyPartAnAttachment(p));
+ }
+
+ // No Content-Disposition field
+ void testIsBodyPartAnAttachment3() {
+
+ vmime::string data = "Content-Type: application/octet-stream\r\n\r\nFoo\r\n";
+
+ vmime::shared_ptr <vmime::bodyPart> p = vmime::make_shared <vmime::bodyPart>();
+ p->parse(data);
+
+ VASSERT_EQ("1", true, vmime::attachmentHelper::isBodyPartAnAttachment(p));
+ }
+
+ // Content-Disposition: attachment
+ // Content-Id field present
+ void testIsBodyPartAnAttachment4() {
+
+ vmime::string data = "Content-Disposition: attachment\r\n"
+ "Content-Type: application/octet-stream\r\n"
+ "Content-Id: bar\r\n"
+ "\r\nFoo\r\n";
+
+ vmime::shared_ptr <vmime::bodyPart> p = vmime::make_shared <vmime::bodyPart>();
+ p->parse(data);
+
+ VASSERT_EQ("1", false, vmime::attachmentHelper::isBodyPartAnAttachment(p));
+ }
+
+ void testGetBodyPartAttachment() {
+
+ vmime::string data =
+ "Content-Type: image/jpeg\r\n"
+ "Content-Description: foobar\r\n"
+ "Content-Transfer-Encoding: x-baz\r\n"
+ "Content-Disposition: attachment; filename=\"foobar.baz\"\r\n"
+ "\r\n"
+ "Foo bar baz";
+
+ vmime::shared_ptr <vmime::bodyPart> part = vmime::make_shared <vmime::bodyPart>();
+ part->parse(data);
+
+ vmime::shared_ptr <const vmime::attachment> att =
+ vmime::attachmentHelper::getBodyPartAttachment(part);
+
+ VASSERT_EQ("1", "image/jpeg", att->getType().generate());
+ VASSERT_EQ("2", "foobar", att->getDescription().generate());
+ VASSERT_EQ("3", "x-baz", att->getEncoding().generate());
+ VASSERT_EQ("4", "foobar.baz", att->getName().generate());
+
+ vmime::string attData;
+ vmime::utility::outputStreamStringAdapter out(attData);
+ att->getData()->extractRaw(out); // 'x-baz' encoding not supported
+
+ VASSERT_EQ("5", "Foo bar baz", attData);
+
+ //VASSERT_EQ("6", part, att->getPart());
+ VASSERT_EQ("6", part->generate(), vmime::dynamicCast <const vmime::component>(att->getPart())->generate());
+ //VASSERT_EQ("7", part->getHeader(), att->getHeader());
+ VASSERT_EQ("7", part->getHeader()->generate(), att->getHeader()->generate());
+ }
+
+ void testAddAttachmentMessage1() {
+
+ const vmime::string data =
+"Subject: Test message\r\n"
+"Content-Type: text/plain\r\n"
+"\r\n"
+"Message body";
+
+ vmime::shared_ptr <vmime::message> msg = vmime::make_shared <vmime::message>();
+ msg->parse(data);
+
+ const vmime::string attData =
+"Subject: Attached message\r\n"
+"Content-Type: text/plain\r\n"
+"Content-Transfer-Encoding: base64\r\n"
+"\r\n"
+"QXR0YWNoZWQgbWVzc2FnZSBib2R5";
+
+ vmime::shared_ptr <vmime::message> amsg = vmime::make_shared <vmime::message>();
+ amsg->parse(attData);
+
+ vmime::attachmentHelper::addAttachment(msg, amsg);
+
+ VASSERT_EQ("1", "multipart/mixed[text/plain,message/rfc822]", getStructure(msg));
+ VASSERT_EQ("2", "Message body", extractBodyContents(msg->getBody()->getPartAt(0)));
+
+ // Ensure message has been encoded properly
+ vmime::shared_ptr <const vmime::bodyPart> attPart = msg->getBody()->getPartAt(1);
+ vmime::shared_ptr <const vmime::contentHandler> attCth = attPart->getBody()->getContents();
+
+ vmime::string attDataOut;
+ vmime::utility::outputStreamStringAdapter attDataOutOs(attDataOut);
+
+ attCth->extract(attDataOutOs);
+
+ vmime::shared_ptr <vmime::message> amsgOut = vmime::make_shared <vmime::message>();
+ amsgOut->parse(attDataOut);
+
+ vmime::shared_ptr <vmime::header> hdr = amsgOut->getHeader();
+
+ VASSERT_EQ("3", "Attached message", hdr->Subject()->getValue <vmime::text>()->generate());
+ VASSERT_EQ("4", "Attached message body", extractBodyContents(amsgOut));
+ }
+
+ void testGetBodyPartAttachmentMessage() {
+
+ const vmime::string data =
+"Subject: Test message\r\n"
+"Content-Type: multipart/mixed; boundary=\"foo\"\r\n"
+"\r\n"
+"--foo\r\n"
+"Content-Type: message/rfc822\r\n"
+"\r\n"
+"Subject: Attached message\r\n"
+"\r\n"
+"Attached message body\r\n"
+"--foo\r\n"
+"Content-Type: text/plain\r\n"
+"\r\n"
+"FooBar\r\n"
+"--foo--\r\n";
+
+ vmime::shared_ptr <vmime::message> msg = vmime::make_shared <vmime::message>();
+ msg->parse(data);
+
+ VASSERT_EQ("0", 2, msg->getBody()->getPartCount());
+
+ vmime::shared_ptr <const vmime::attachment> att =
+ vmime::attachmentHelper::getBodyPartAttachment(msg->getBody()->getPartAt(0));
+
+ VASSERT("1", att != NULL);
+
+ vmime::shared_ptr <const vmime::messageAttachment> msgAtt =
+ vmime::dynamicCast <const vmime::messageAttachment>(att);
+
+ VASSERT("2", msgAtt != NULL);
+
+ vmime::shared_ptr <vmime::message> amsg = msgAtt->getMessage();
+ vmime::shared_ptr <vmime::header> hdr = amsg->getHeader();
+
+ VASSERT_EQ("3", "Attached message", hdr->Subject()->getValue <vmime::text>()->generate());
+ VASSERT_EQ("4", "Attached message body", extractBodyContents(amsg));
+ }
+
+VMIME_TEST_SUITE_END
diff --git a/vmime-master/tests/parser/bodyPartTest.cpp b/vmime-master/tests/parser/bodyPartTest.cpp
new file mode 100644
index 0000000..3aaadd0
--- /dev/null
+++ b/vmime-master/tests/parser/bodyPartTest.cpp
@@ -0,0 +1,414 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "tests/testUtils.hpp"
+
+
+VMIME_TEST_SUITE_BEGIN(bodyPartTest)
+
+ VMIME_TEST_LIST_BEGIN
+ VMIME_TEST(testParse)
+ VMIME_TEST(testGenerate)
+ VMIME_TEST(testParseGuessBoundary)
+ VMIME_TEST(testParseGuessBoundaryWithTransportPadding)
+ VMIME_TEST(testParseMissingLastBoundary)
+ VMIME_TEST(testPrologEpilog)
+ VMIME_TEST(testPrologEncoding)
+ VMIME_TEST(testSuccessiveBoundaries)
+ VMIME_TEST(testTransportPaddingInBoundary)
+ VMIME_TEST(testGenerate7bit)
+ VMIME_TEST(testTextUsageForQPEncoding)
+ VMIME_TEST(testParseVeryBigMessage)
+ VMIME_TEST(testParseBoundaryPrefix)
+ VMIME_TEST_LIST_END
+
+
+ static const vmime::string extractComponentString(
+ const vmime::string& buffer,
+ const vmime::component& c
+ ) {
+
+ return vmime::string(
+ buffer.begin() + c.getParsedOffset(),
+ buffer.begin() + c.getParsedOffset() + c.getParsedLength()
+ );
+ }
+
+ static const vmime::string extractContents(
+ const vmime::shared_ptr <const vmime::contentHandler>& cts
+ ) {
+
+ std::ostringstream oss;
+ vmime::utility::outputStreamAdapter os(oss);
+
+ cts->extract(os);
+
+ return oss.str();
+ }
+
+
+ void testParse() {
+
+ vmime::string str1 = "HEADER\r\n\r\nBODY";
+ vmime::bodyPart p1;
+ p1.parse(str1);
+
+ VASSERT_EQ("1", "HEADER\r\n\r\n", extractComponentString(str1, *p1.getHeader()));
+ VASSERT_EQ("2", "BODY", extractComponentString(str1, *p1.getBody()));
+
+ vmime::string str2 = "HEADER\n\nBODY";
+ vmime::bodyPart p2;
+ p2.parse(str2);
+
+ VASSERT_EQ("3", "HEADER\n\n", extractComponentString(str2, *p2.getHeader()));
+ VASSERT_EQ("4", "BODY", extractComponentString(str2, *p2.getBody()));
+
+ vmime::string str3 = "HEADER\r\n\nBODY";
+ vmime::bodyPart p3;
+ p3.parse(str3);
+
+ VASSERT_EQ("5", "HEADER\r\n\n", extractComponentString(str3, *p3.getHeader()));
+ VASSERT_EQ("6", "BODY", extractComponentString(str3, *p3.getBody()));
+ }
+
+ void testParseMissingLastBoundary() {
+
+ vmime::string str =
+ "Content-Type: multipart/mixed; boundary=\"MY-BOUNDARY\""
+ "\r\n\r\n"
+ "--MY-BOUNDARY\r\nHEADER1\r\n\r\nBODY1\r\n"
+ "--MY-BOUNDARY\r\nHEADER2\r\n\r\nBODY2";
+
+ vmime::bodyPart p;
+ p.parse(str);
+
+ VASSERT_EQ("count", 2, p.getBody()->getPartCount());
+
+ VASSERT_EQ("part1-body", "BODY1", extractContents(p.getBody()->getPartAt(0)->getBody()->getContents()));
+ VASSERT_EQ("part2-body", "BODY2", extractContents(p.getBody()->getPartAt(1)->getBody()->getContents()));
+ }
+
+ void testGenerate() {
+
+ vmime::bodyPart p1;
+ p1.getHeader()->getField("Foo")->setValue(vmime::string("bar"));
+ p1.getBody()->setContents(vmime::make_shared <vmime::stringContentHandler>("Baz"));
+
+ VASSERT_EQ("1", "Foo: bar\r\n\r\nBaz", p1.generate());
+ }
+
+ void testPrologEpilog() {
+
+ const char testMail[] =
+ "To: test@vmime.org\r\n"
+ "From: test@vmime.org\r\n"
+ "Subject: Prolog and epilog test\r\n"
+ "Content-Type: multipart/mixed; \r\n"
+ " boundary=\"=_boundary\"\r\n"
+ "\r\n"
+ "Prolog text\r\n"
+ "--=_boundary\r\n"
+ "Content-Type: text/plain\r\n"
+ "\r\n"
+ "Part1\r\n"
+ "--=_boundary--\r\n"
+ "Epilog text";
+
+ vmime::bodyPart part;
+ part.parse(testMail);
+
+ VASSERT_EQ("prolog", "Prolog text", part.getBody()->getPrologText());
+ VASSERT_EQ("epilog", "Epilog text", part.getBody()->getEpilogText());
+ }
+
+ // Test for bug fix: prolog should not be encoded
+ // http://sourceforge.net/tracker/?func=detail&atid=525568&aid=3174903&group_id=69724
+ void testPrologEncoding() {
+
+ const char testmail[] =
+ "To: test@vmime.org\r\n"
+ "From: test@vmime.org\r\n"
+ "Subject: Prolog encoding test\r\n"
+ "Content-Type: multipart/mixed; \r\n"
+ " boundary=\"=_+ZWjySayKqSf2CyrfnNpaAcO6-G1HpoXdHZ4YyswAWqEY39Q\"\r\n"
+ "\r\n"
+ "This is a multi-part message in MIME format. Your mail reader does not\r\n"
+ "understand MIME message format.\r\n"
+ "--=_+ZWjySayKqSf2CyrfnNpaAcO6-G1HpoXdHZ4YyswAWqEY39Q\r\n"
+ "Content-Type: text/html; charset=windows-1251\r\n"
+ "Content-Transfer-Encoding: quoted-printable\r\n"
+ "\r\n"
+ "=DD=F2=EE =F2=E5=EA=F1=F2=EE=E2=E0=FF =F7=E0=F1=F2=FC =F1=EB=EE=E6=ED=EE=E3=\r\n"
+ "=EE =F1=EE=EE=E1=F9=E5=ED=E8=FF\r\n"
+ "--=_+ZWjySayKqSf2CyrfnNpaAcO6-G1HpoXdHZ4YyswAWqEY39Q\r\n"
+ "Content-Type: application/octet-stream; charset=windows-1251\r\n"
+ "Content-Disposition: attachment; filename=FNS.zip\r\n"
+ "Content-Transfer-Encoding: base64\r\n"
+ "\r\n"
+ "UEsDBB...snap...EEAAAAAA==\r\n"
+ "--=_+ZWjySayKqSf2CyrfnNpaAcO6-G1HpoXdHZ4YyswAWqEY39Q--\r\n"
+ "Epilog text";
+
+ vmime::shared_ptr<vmime::message> msg = vmime::make_shared<vmime::message>();
+
+ std::string istr(testmail);
+
+ std::string ostr;
+ vmime::utility::outputStreamStringAdapter out(ostr);
+
+ for (int i = 0 ; i < 10 ; ++i) {
+
+ ostr.clear();
+
+ msg->parse(istr);
+ msg->generate(out);
+
+ istr = ostr;
+ }
+
+ VASSERT_EQ("prolog", "This is a multi-part message in MIME format. Your mail reader"
+ " does not understand MIME message format.", msg->getBody()->getPrologText());
+ VASSERT_EQ("epilog", "Epilog text", msg->getBody()->getEpilogText());
+ }
+
+ void testSuccessiveBoundaries() {
+
+ vmime::string str =
+ "Content-Type: multipart/mixed; boundary=\"MY-BOUNDARY\""
+ "\r\n\r\n"
+ "--MY-BOUNDARY\r\nHEADER1\r\n\r\nBODY1\r\n"
+ "--MY-BOUNDARY\r\n"
+ "--MY-BOUNDARY--\r\n";
+
+ vmime::bodyPart p;
+ p.parse(str);
+
+ VASSERT_EQ("count", 2, p.getBody()->getPartCount());
+
+ VASSERT_EQ("part1-body", "BODY1", extractContents(p.getBody()->getPartAt(0)->getBody()->getContents()));
+ VASSERT_EQ("part2-body", "", extractContents(p.getBody()->getPartAt(1)->getBody()->getContents()));
+ }
+
+ void testTransportPaddingInBoundary() {
+
+ vmime::string str =
+ "Content-Type: multipart/mixed; boundary=\"MY-BOUNDARY\""
+ "\r\n\r\n"
+ "--MY-BOUNDARY \t \r\nHEADER1\r\n\r\nBODY1\r\n"
+ "--MY-BOUNDARY\r\n"
+ "--MY-BOUNDARY-- \r\n";
+
+ vmime::bodyPart p;
+ p.parse(str);
+
+ VASSERT_EQ("count", 2, p.getBody()->getPartCount());
+
+ VASSERT_EQ("part1-body", "BODY1", extractContents(p.getBody()->getPartAt(0)->getBody()->getContents()));
+ VASSERT_EQ("part2-body", "", extractContents(p.getBody()->getPartAt(1)->getBody()->getContents()));
+ }
+
+ /** Ensure '7bit' encoding is used when body is 7-bit only. */
+ void testGenerate7bit() {
+
+ vmime::shared_ptr <vmime::plainTextPart> p1 = vmime::make_shared <vmime::plainTextPart>();
+ p1->setText(vmime::make_shared <vmime::stringContentHandler>("Part1 is US-ASCII only."));
+
+ vmime::shared_ptr <vmime::message> msg = vmime::make_shared <vmime::message>();
+ p1->generateIn(msg, msg);
+
+ vmime::shared_ptr <vmime::header> header1 = msg->getBody()->getPartAt(0)->getHeader();
+ VASSERT_EQ("1", "7bit", header1->ContentTransferEncoding()->getValue()->generate());
+ }
+
+ void testTextUsageForQPEncoding() {
+
+ vmime::shared_ptr <vmime::plainTextPart> part = vmime::make_shared <vmime::plainTextPart>();
+ part->setText(vmime::make_shared <vmime::stringContentHandler>("Part1-line1\r\nPart1-line2\r\n\x89"));
+
+ vmime::shared_ptr <vmime::message> msg = vmime::make_shared <vmime::message>();
+ part->generateIn(msg, msg);
+
+ vmime::shared_ptr <vmime::body> body = msg->getBody()->getPartAt(0)->getBody();
+ vmime::shared_ptr <vmime::header> header = msg->getBody()->getPartAt(0)->getHeader();
+
+ std::ostringstream oss;
+ vmime::utility::outputStreamAdapter os(oss);
+ body->generate(os, 80);
+
+ VASSERT_EQ("1", "quoted-printable", header->ContentTransferEncoding()->getValue()->generate());
+
+ // This should *NOT* be:
+ // Part1-line1=0D=0APart1-line2=0D=0A=89
+ VASSERT_EQ("2", "Part1-line1\r\nPart1-line2\r\n=89", oss.str());
+ }
+
+ void testParseGuessBoundary() {
+
+ // Boundary is not specified in "Content-Type" field
+ // Parser will try to guess it from message contents.
+
+ vmime::string str =
+ "Content-Type: multipart/mixed"
+ "\r\n\r\n"
+ "--UNKNOWN-BOUNDARY\r\nHEADER1\r\n\r\nBODY1\r\n"
+ "--UNKNOWN-BOUNDARY\r\nHEADER2\r\n\r\nBODY2\r\n"
+ "--UNKNOWN-BOUNDARY--";
+
+ vmime::bodyPart p;
+ p.parse(str);
+
+ VASSERT_EQ("count", 2, p.getBody()->getPartCount());
+
+ VASSERT_EQ("part1-body", "BODY1", extractContents(p.getBody()->getPartAt(0)->getBody()->getContents()));
+ VASSERT_EQ("part2-body", "BODY2", extractContents(p.getBody()->getPartAt(1)->getBody()->getContents()));
+ }
+
+ void testParseGuessBoundaryWithTransportPadding() {
+
+ // Boundary is not specified in "Content-Type" field
+ // Parser will try to guess it from message contents.
+ // Transport padding white spaces should be ignored.
+
+ vmime::string str =
+ "Content-Type: multipart/mixed"
+ "\r\n\r\n"
+ "--UNKNOWN-BOUNDARY \t \r\nHEADER1\r\n\r\nBODY1\r\n"
+ "--UNKNOWN-BOUNDARY\r\nHEADER2\r\n\r\nBODY2\r\n"
+ "--UNKNOWN-BOUNDARY--";
+
+ vmime::bodyPart p;
+ p.parse(str);
+
+ VASSERT_EQ("count", 2, p.getBody()->getPartCount());
+
+ VASSERT_EQ("part1-body", "BODY1", extractContents(p.getBody()->getPartAt(0)->getBody()->getContents()));
+ VASSERT_EQ("part2-body", "BODY2", extractContents(p.getBody()->getPartAt(1)->getBody()->getContents()));
+ }
+
+ void testParseVeryBigMessage() {
+
+ // When parsing from a seekable input stream, body contents should not
+ // be kept in memory in a "stringContentHandler" object. Instead, content
+ // should be accessible via a "streamContentHandler" object.
+
+ static const std::string BODY1_BEGIN = "BEGIN1BEGIN1BEGIN1";
+ static const std::string BODY1_LINE = "BODY1BODY1BODY1BODY1BODY1BODY1BODY1BODY1BODY1BODY1BODY1BODY1BODY1";
+ static const std::string BODY1_END = "END1END1";
+ static const unsigned int BODY1_REPEAT = 35000;
+ static const size_t BODY1_LENGTH =
+ BODY1_BEGIN.length() + BODY1_LINE.length() * BODY1_REPEAT + BODY1_END.length();
+
+ static const std::string BODY2_LINE = "BODY2BODY2BODY2BODY2BODY2BODY2BODY2BODY2BODY2BODY2BODY2BODY2BODY2";
+ static const unsigned int BODY2_REPEAT = 20000;
+
+ std::ostringstream oss;
+ oss << "Content-Type: multipart/mixed; boundary=\"MY-BOUNDARY\""
+ << "\r\n\r\n"
+ << "--MY-BOUNDARY\r\n"
+ << "HEADER1\r\n"
+ << "\r\n";
+
+ oss << BODY1_BEGIN;
+
+ for (unsigned int i = 0 ; i < BODY1_REPEAT ; ++i) {
+ oss << BODY1_LINE;
+ }
+
+ oss << BODY1_END;
+
+ oss << "\r\n"
+ << "--MY-BOUNDARY\r\n"
+ << "HEADER2\r\n"
+ << "\r\n";
+
+ for (unsigned int i = 0 ; i < BODY2_REPEAT ; ++i) {
+ oss << BODY2_LINE;
+ }
+
+ oss << "\r\n"
+ << "--MY-BOUNDARY--\r\n";
+
+ vmime::shared_ptr <vmime::utility::inputStreamStringAdapter> is =
+ vmime::make_shared <vmime::utility::inputStreamStringAdapter>(oss.str());
+
+ vmime::shared_ptr <vmime::message> msg = vmime::make_shared <vmime::message>();
+ msg->parse(is, oss.str().length());
+
+ vmime::shared_ptr <vmime::body> body1 = msg->getBody()->getPartAt(0)->getBody();
+ vmime::shared_ptr <const vmime::contentHandler> body1Cts = body1->getContents();
+
+ vmime::shared_ptr <vmime::body> body2 = msg->getBody()->getPartAt(1)->getBody();
+ vmime::shared_ptr <const vmime::contentHandler> body2Cts = body2->getContents();
+
+ vmime::string body1CtsExtracted;
+ vmime::utility::outputStreamStringAdapter body1CtsExtractStream(body1CtsExtracted);
+ body1Cts->extract(body1CtsExtractStream);
+
+ VASSERT_EQ("1.1", BODY1_LENGTH, body1Cts->getLength());
+ VASSERT("1.2", vmime::dynamicCast <const vmime::streamContentHandler>(body1Cts) != NULL);
+ VASSERT_EQ("1.3", BODY1_LENGTH, body1CtsExtracted.length());
+ VASSERT_EQ("1.4", BODY1_BEGIN, body1CtsExtracted.substr(0, BODY1_BEGIN.length()));
+ VASSERT_EQ("1.5", BODY1_END, body1CtsExtracted.substr(BODY1_LENGTH - BODY1_END.length(), BODY1_END.length()));
+
+ VASSERT_EQ("2.1", BODY2_LINE.length() * BODY2_REPEAT, body2Cts->getLength());
+ VASSERT("2.2", vmime::dynamicCast <const vmime::streamContentHandler>(body2Cts) != NULL);
+ }
+
+ void testParseBoundaryPrefix() {
+ /*
+ * Clients are not supposed to create boundary identifiers that
+ * contain a prefix of another (RFC 2046 section 5.1), but alas
+ * CANCOM FortiMail produces this garbage.
+ */
+ vmime::string str =
+ "Content-Type: multipart/related; boundary=\"--b12\"\r\n"
+ "\r\n"
+ "----b12\r\n"
+ "Content-Type: multipart/alternative; boundary=\"--b12-1\"\r\n"
+ "\r\n"
+ "----b12-1\r\n"
+ "Content-Type: text/plain; charset=utf-8\r\n"
+ "\r\n"
+ "P11\r\n"
+ "----b12-1\r\n"
+ "Content-Type: text/html; charset=utf-8\r\n"
+ "\r\n"
+ "P12\r\n"
+ "----b12-1--\r\n"
+ "----b12\r\n"
+ "\r\n"
+ "P2\r\n"
+ "----b12--\r\n";
+
+ vmime::bodyPart relco;
+ relco.parse(str);
+ auto relbd = relco.getBody();
+ VASSERT_EQ("global-partcount", 2, relbd->getPartCount());
+ auto altbd = relbd->getPartAt(0)->getBody();
+ VASSERT_EQ("part1-partcount", 2, altbd->getPartCount());
+ VASSERT_EQ("part1.1-body", "P11", extractContents(altbd->getPartAt(0)->getBody()->getContents()));
+ VASSERT_EQ("part1.2-body", "P12", extractContents(altbd->getPartAt(1)->getBody()->getContents()));
+ VASSERT_EQ("part2-body", "P2", extractContents(relbd->getPartAt(1)->getBody()->getContents()));
+ }
+
+VMIME_TEST_SUITE_END
diff --git a/vmime-master/tests/parser/bodyTest.cpp b/vmime-master/tests/parser/bodyTest.cpp
new file mode 100644
index 0000000..31054f3
--- /dev/null
+++ b/vmime-master/tests/parser/bodyTest.cpp
@@ -0,0 +1,79 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "tests/testUtils.hpp"
+
+
+VMIME_TEST_SUITE_BEGIN(bodyTest)
+
+ VMIME_TEST_LIST_BEGIN
+ VMIME_TEST(testGenerate_Text)
+ VMIME_TEST(testGenerate_NonText)
+ VMIME_TEST_LIST_END
+
+ void testGenerate_Text() {
+
+ // RFC-2015: [Quoted-Printable encoding] A line break in a text body,
+ // represented as a CRLF sequence in the text canonical form, must be
+ // represented by a line break which is also a CRLF sequence, in the
+ // Quoted-Printable encoding
+
+ vmime::bodyPart p;
+ p.getBody()->setContents(
+ vmime::make_shared <vmime::stringContentHandler>(
+ "Foo éé\r\né bar\r\nbaz"
+ ),
+ vmime::mediaType("text", "plain"),
+ vmime::charset("utf-8"),
+ vmime::encoding("quoted-printable")
+ );
+
+ VASSERT_EQ(
+ "generate",
+ "Foo =C3=A9=C3=A9\r\n"
+ "=C3=A9 bar\r\n"
+ "baz",
+ p.getBody()->generate()
+ );
+ }
+
+ void testGenerate_NonText() {
+
+ vmime::bodyPart p;
+ p.getBody()->setContents(
+ vmime::make_shared <vmime::stringContentHandler>(
+ "Binary\xfa\xfb\r\ndata\r\n\r\n\xfc"
+ ),
+ vmime::mediaType("application", "octet-stream"),
+ vmime::charset("utf-8"),
+ vmime::encoding("quoted-printable")
+ );
+
+ VASSERT_EQ(
+ "generate",
+ "Binary=FA=FB=0D=0Adata=0D=0A=0D=0A=FC",
+ p.getBody()->generate()
+ );
+ }
+
+VMIME_TEST_SUITE_END
diff --git a/vmime-master/tests/parser/charsetFilteredOutputStreamTest.cpp b/vmime-master/tests/parser/charsetFilteredOutputStreamTest.cpp
new file mode 100644
index 0000000..0ebd83a
--- /dev/null
+++ b/vmime-master/tests/parser/charsetFilteredOutputStreamTest.cpp
@@ -0,0 +1,213 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "tests/testUtils.hpp"
+
+#include "vmime/charset.hpp"
+#include "vmime/charsetConverter.hpp"
+
+#include "charsetTestSuites.hpp"
+
+
+VMIME_TEST_SUITE_BEGIN(charsetFilteredOutputStreamTest)
+
+ VMIME_TEST_LIST_BEGIN
+ VMIME_TEST(testInputBufferUnderflow)
+ VMIME_TEST(testInvalidInput1)
+ VMIME_TEST(testStreamCopy)
+ VMIME_TEST(testOneByteAtTime)
+ VMIME_TEST(testVariableInputChunk)
+ VMIME_TEST_LIST_END
+
+
+ void testInputBufferUnderflow() {
+
+ vmime::shared_ptr <vmime::charsetConverter> cc =
+ vmime::charsetConverter::create("utf-8", "iso-8859-1");
+
+ vmime::string output;
+ vmime::utility::outputStreamStringAdapter os(output);
+ vmime::shared_ptr <vmime::utility::filteredOutputStream> cfos = cc->getFilteredOutputStream(os);
+
+ VASSERT_NOT_NULL("filteredOutputStream availability", cfos);
+
+ // føo = 66 c3 b8 6f [UTF8]
+ // føo = 66 f8 6f [latin1]
+
+ cfos->write("\x66\xc3", 2);
+
+ // Incomplete UTF-8 sequence was not converted
+ VASSERT_EQ("chunk 1", toHex("f"), toHex(output));
+
+ // Write second byte of UTF-8 sequence
+ cfos->write("\xb8\x6f", 2);
+
+ VASSERT_EQ("chunk 2", toHex("f\xf8o"), toHex(output));
+ }
+
+ void testInvalidInput1() {
+
+ vmime::string in("foo\xab\xcd\xef bar");
+ vmime::string expectedOut("foo??? bar");
+
+ vmime::string actualOut;
+ vmime::utility::outputStreamStringAdapter osa(actualOut);
+
+ vmime::shared_ptr <vmime::charsetConverter> conv =
+ vmime::charsetConverter::create(vmime::charset("utf-8"), vmime::charset("iso-8859-1"));
+
+ vmime::shared_ptr <vmime::utility::charsetFilteredOutputStream> os =
+ conv->getFilteredOutputStream(osa);
+
+ VASSERT_NOT_NULL("filteredOutputStream availability", os);
+
+ vmime::utility::inputStreamStringAdapter is(in);
+
+ vmime::byte_t buffer[16];
+
+ for (int i = 0 ; !is.eof() ; ++i)
+ os->write(buffer, is.read(buffer, 1));
+
+ os->flush();
+
+ VASSERT_EQ("1", toHex(expectedOut), toHex(actualOut));
+ }
+
+ // Using 'bufferedStreamCopy'
+ void testStreamCopy() {
+
+ for (unsigned int i = 0 ; i < charsetTestSuitesCount ; ++i) {
+
+ const charsetTestSuiteStruct& entry = charsetTestSuites[i];
+
+ std::ostringstream testName;
+ testName << i << ": " << entry.fromCharset << " -> " << entry.toCharset;
+
+ const unsigned long inLength = (entry.fromLength == 0 ? strlen(entry.fromBytes) : entry.fromLength);
+ vmime::string in(entry.fromBytes, entry.fromBytes + inLength);
+
+ const unsigned long outLength = (entry.toLength == 0 ? strlen(entry.toBytes) : entry.toLength);
+ vmime::string expectedOut(entry.toBytes, entry.toBytes + outLength);
+
+ vmime::string actualOut;
+ vmime::utility::outputStreamStringAdapter osa(actualOut);
+
+ vmime::shared_ptr <vmime::charsetConverter> conv =
+ vmime::charsetConverter::create(entry.fromCharset, entry.toCharset);
+
+ vmime::shared_ptr <vmime::utility::charsetFilteredOutputStream> os =
+ conv->getFilteredOutputStream(osa);
+
+ VASSERT_NOT_NULL("filteredOutputStream availability", os);
+
+ vmime::utility::inputStreamStringAdapter is(in);
+
+ vmime::utility::bufferedStreamCopy(is, *os);
+
+ os->flush();
+
+ VASSERT_EQ(testName.str(), toHex(expectedOut), toHex(actualOut));
+ }
+ }
+
+ // One byte at a time
+ void testOneByteAtTime() {
+
+ for (unsigned int i = 0 ; i < charsetTestSuitesCount ; ++i) {
+
+ const charsetTestSuiteStruct& entry = charsetTestSuites[i];
+
+ std::ostringstream testName;
+ testName << i << ": " << entry.fromCharset << " -> " << entry.toCharset;
+
+ const unsigned long inLength = (entry.fromLength == 0 ? strlen(entry.fromBytes) : entry.fromLength);
+ vmime::string in(entry.fromBytes, entry.fromBytes + inLength);
+
+ const unsigned long outLength = (entry.toLength == 0 ? strlen(entry.toBytes) : entry.toLength);
+ vmime::string expectedOut(entry.toBytes, entry.toBytes + outLength);
+
+ vmime::string actualOut;
+ vmime::utility::outputStreamStringAdapter osa(actualOut);
+
+ vmime::shared_ptr <vmime::charsetConverter> conv =
+ vmime::charsetConverter::create(entry.fromCharset, entry.toCharset);
+
+ vmime::shared_ptr <vmime::utility::charsetFilteredOutputStream> os =
+ conv->getFilteredOutputStream(osa);
+
+ VASSERT_NOT_NULL("filteredOutputStream availability", os);
+
+ vmime::utility::inputStreamStringAdapter is(in);
+
+ vmime::byte_t buffer[16];
+
+ for (int i = 0 ; !is.eof() ; ++i)
+ os->write(buffer, is.read(buffer, 1));
+
+ os->flush();
+
+ VASSERT_EQ(testName.str(), toHex(expectedOut), toHex(actualOut));
+ }
+ }
+
+ // Variable chunks
+ void testVariableInputChunk() {
+
+ for (unsigned int i = 0 ; i < charsetTestSuitesCount ; ++i) {
+
+ const charsetTestSuiteStruct& entry = charsetTestSuites[i];
+
+ std::ostringstream testName;
+ testName << i << ": " << entry.fromCharset << " -> " << entry.toCharset;
+
+ const unsigned long inLength = (entry.fromLength == 0 ? strlen(entry.fromBytes) : entry.fromLength);
+ vmime::string in(entry.fromBytes, entry.fromBytes + inLength);
+
+ const unsigned long outLength = (entry.toLength == 0 ? strlen(entry.toBytes) : entry.toLength);
+ vmime::string expectedOut(entry.toBytes, entry.toBytes + outLength);
+
+ vmime::string actualOut;
+ vmime::utility::outputStreamStringAdapter osa(actualOut);
+
+ vmime::shared_ptr <vmime::charsetConverter> conv =
+ vmime::charsetConverter::create(entry.fromCharset, entry.toCharset);
+
+ vmime::shared_ptr <vmime::utility::charsetFilteredOutputStream> os =
+ conv->getFilteredOutputStream(osa);
+
+ VASSERT_NOT_NULL("filteredOutputStream availability", os);
+
+ vmime::utility::inputStreamStringAdapter is(in);
+
+ vmime::byte_t buffer[16];
+
+ for (int i = 0 ; !is.eof() ; ++i)
+ os->write(buffer, is.read(buffer, (i % 5) + 1));
+
+ os->flush();
+
+ VASSERT_EQ(testName.str(), toHex(expectedOut), toHex(actualOut));
+ }
+ }
+
+VMIME_TEST_SUITE_END
diff --git a/vmime-master/tests/parser/charsetTest.cpp b/vmime-master/tests/parser/charsetTest.cpp
new file mode 100644
index 0000000..e44bef5
--- /dev/null
+++ b/vmime-master/tests/parser/charsetTest.cpp
@@ -0,0 +1,252 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include <algorithm>
+
+#include "tests/testUtils.hpp"
+
+#include "charsetTestSuites.hpp"
+
+
+VMIME_TEST_SUITE_BEGIN(charsetTest)
+
+ VMIME_TEST_LIST_BEGIN
+ // Test valid input
+ VMIME_TEST(testConvertStringValid)
+ VMIME_TEST(testConvertStreamValid)
+ VMIME_TEST(testEncodingHebrew1255)
+
+ // IDNA
+ VMIME_TEST(testEncodeIDNA)
+ VMIME_TEST(testDecodeIDNA)
+
+ VMIME_TEST(testUTF7Support)
+
+ VMIME_TEST(testReplaceInvalidSequence)
+ VMIME_TEST(testStopOnInvalidSequence)
+
+ VMIME_TEST(testStatus)
+ VMIME_TEST(testStatusWithInvalidSequence)
+
+ VMIME_TEST(testIsValidText)
+ VMIME_TEST_LIST_END
+
+
+ void testConvertStringValid() {
+
+ for (unsigned int i = 0 ; i < charsetTestSuitesCount ; ++i) {
+
+ const charsetTestSuiteStruct& entry = charsetTestSuites[i];
+
+ std::ostringstream testName;
+ testName << i << ": " << entry.fromCharset << " -> " << entry.toCharset;
+
+ const unsigned long inLength = (entry.fromLength == 0 ? strlen(entry.fromBytes) : entry.fromLength);
+ vmime::string in(entry.fromBytes, entry.fromBytes + inLength);
+
+ const unsigned long outLength = (entry.toLength == 0 ? strlen(entry.toBytes) : entry.toLength);
+ vmime::string expectedOut(entry.toBytes, entry.toBytes + outLength);
+
+ vmime::string actualOut;
+
+ vmime::charset::convert
+ (in, actualOut, entry.fromCharset, entry.toCharset);
+
+ VASSERT_EQ(testName.str(), toHex(expectedOut), toHex(actualOut));
+ }
+ }
+
+ void testConvertStreamValid() {
+
+ for (unsigned int i = 0 ; i < charsetTestSuitesCount ; ++i) {
+
+ const charsetTestSuiteStruct& entry = charsetTestSuites[i];
+
+ std::ostringstream testName;
+ testName << i << ": " << entry.fromCharset << " -> " << entry.toCharset;
+
+ const unsigned long inLength = (entry.fromLength == 0 ? strlen(entry.fromBytes) : entry.fromLength);
+ vmime::string in(entry.fromBytes, entry.fromBytes + inLength);
+
+ const unsigned long outLength = (entry.toLength == 0 ? strlen(entry.toBytes) : entry.toLength);
+ vmime::string expectedOut(entry.toBytes, entry.toBytes + outLength);
+
+ vmime::string actualOut;
+ vmime::utility::outputStreamStringAdapter os(actualOut);
+
+ vmime::utility::inputStreamStringAdapter is(in);
+
+ vmime::charset::convert(is, os, entry.fromCharset, entry.toCharset);
+
+ os.flush();
+
+ VASSERT_EQ(testName.str(), toHex(expectedOut), toHex(actualOut));
+ }
+ }
+
+ void testEncodingHebrew1255() {
+
+ // hewbrew string in windows-1255 charset
+ const char data[] = "\xe9\xf9\xf7\xf8\xe9\xf9\xf8\xf7\xe9\xe9\xf9";
+ vmime::word w = vmime::word(data, "windows-1255");
+ vmime::string encoded = w.generate();
+ // less than 60% ascii, base64 received
+ VASSERT_EQ("1", "=?windows-1255?B?6fn3+On5+Pfp6fk=?=", encoded);
+ }
+
+ static const vmime::string convertHelper(
+ const vmime::string& in,
+ const vmime::charset& csrc,
+ const vmime::charset& cdest,
+ const vmime::charsetConverterOptions& opts = vmime::charsetConverterOptions(),
+ vmime::charsetConverter::status* st = NULL
+ ) {
+
+ vmime::shared_ptr <vmime::charsetConverter> conv =
+ vmime::charsetConverter::create(csrc, cdest, opts);
+
+ vmime::string out;
+ conv->convert(in, out, st);
+
+ return out;
+ }
+
+ void testEncodeIDNA() {
+
+ VASSERT_EQ("1", "xn--espaol-zwa", convertHelper("español", "utf-8", "idna"));
+
+ // Tests from ICANN
+ VASSERT_EQ("2.1", "xn--hxajbheg2az3al", convertHelper("παράδειγμα", "utf-8", "idna"));
+ VASSERT_EQ("2.2", "xn--jxalpdlp", convertHelper("δοκιμή", "utf-8", "idna"));
+
+ VASSERT_EQ("3.1", "xn--mgbh0fb", convertHelper("مثال", "utf-8", "idna"));
+ VASSERT_EQ("3.2", "xn--kgbechtv", convertHelper("إختبار", "utf-8", "idna"));
+ }
+
+ void testDecodeIDNA() {
+
+ VASSERT_EQ("1", "español", convertHelper("xn--espaol-zwa", "idna", "utf-8"));
+
+ // Tests from ICANN
+ VASSERT_EQ("2.1", "παράδειγμα", convertHelper("xn--hxajbheg2az3al", "idna", "utf-8"));
+ VASSERT_EQ("2.2", "δοκιμή", convertHelper("xn--jxalpdlp", "idna", "utf-8"));
+
+ VASSERT_EQ("3.1", "مثال", convertHelper("xn--mgbh0fb", "idna", "utf-8"));
+ VASSERT_EQ("3.2", "إختبار", convertHelper("xn--kgbechtv", "idna", "utf-8"));
+ }
+
+ void testUTF7Support() {
+
+ // Ensure UTF-7 is supported, because it is used for IMAP
+ VASSERT_EQ("1", "VMime +- UTF-7 encoding", convertHelper("VMime + UTF-7 encoding", "utf-8", "utf-7"));
+ VASSERT_EQ("2", "f+APg-o", convertHelper("\x66\xc3\xb8\x6f", "utf-8", "utf-7"));
+ }
+
+ void testReplaceInvalidSequence() {
+
+ vmime::charsetConverterOptions opts;
+ opts.silentlyReplaceInvalidSequences = true;
+ opts.invalidSequence = "?";
+
+ vmime::string res = convertHelper(
+ "\x61\xf1\x80\x80\xe1\x80\xc2\x62\x80\x63\x80\xbf\x64",
+ "utf-8", "iso-8859-1", opts
+ );
+
+ // Result should be in the form "a???b?c??d" or "a??????b?c??d"...
+ // Remove consecutive question marks for easier matching.
+ res.erase(std::unique(res.begin(), res.end()), res.end());
+
+ VASSERT_EQ(
+ "Illegal UTF-8 sequence",
+ "a?b?c?d",
+ res
+ );
+ }
+
+ void testStopOnInvalidSequence() {
+
+ vmime::charsetConverterOptions opts;
+ opts.silentlyReplaceInvalidSequences = false;
+
+ VASSERT_THROW(
+ "Illegal UTF-8 sequence",
+ convertHelper("\x61\xf1\x80\x80\xe1\x80\xc2\x62\x80\x63\x80\xbf\x64", "utf-8", "iso-8859-1", opts),
+ vmime::exceptions::illegal_byte_sequence_for_charset
+ );
+ }
+
+ void testStatus() {
+
+ vmime::charsetConverterOptions opts;
+ opts.silentlyReplaceInvalidSequences = false;
+
+ vmime::charsetConverter::status st;
+
+ // 012345 6 7
+ convertHelper("Gwena\xc3\xabl", "utf-8", "iso-8859-1", opts, &st);
+
+ VASSERT_EQ("inputBytesRead", 8, st.inputBytesRead);
+ VASSERT_EQ("outputBytesWritten", 7, st.outputBytesWritten);
+ }
+
+ void testStatusWithInvalidSequence() {
+
+ vmime::charsetConverterOptions opts;
+ opts.silentlyReplaceInvalidSequences = false;
+
+ vmime::charsetConverter::status st;
+
+ try {
+
+ // 01234 5 6789 0 1
+ convertHelper("Fran\xc3\xa7ois\xf1\x80\x65", "utf-8", "iso-8859-1", opts, &st);
+
+ } catch (vmime::exceptions::illegal_byte_sequence_for_charset& e) {
+
+ } catch (...) {
+
+ throw;
+ }
+
+ VASSERT_EQ("inputBytesRead", 9, st.inputBytesRead);
+ VASSERT_EQ("outputBytesWritten", 8, st.outputBytesWritten);
+ }
+
+ void testIsValidText() {
+
+ // Invalid text
+ const vmime::string invalidText("Fran\xc3\xa7ois\xf1\x80\x65");
+ vmime::string::size_type firstInvalidByte;
+
+ VASSERT_EQ("invalid.isValidText", false, vmime::charset("utf-8").isValidText(invalidText, &firstInvalidByte));
+ VASSERT_EQ("invalid.firstInvalidByte", 9, firstInvalidByte);
+
+ // Valid text
+ const vmime::string validText("Gwena\xc3\xabl");
+
+ VASSERT_EQ("valid.isValidText", true, vmime::charset("utf-8").isValidText(validText, &firstInvalidByte));
+ VASSERT_EQ("valid.firstInvalidByte", 8, firstInvalidByte);
+ }
+
+VMIME_TEST_SUITE_END
diff --git a/vmime-master/tests/parser/charsetTestSuites.hpp b/vmime-master/tests/parser/charsetTestSuites.hpp
new file mode 100644
index 0000000..9653016
--- /dev/null
+++ b/vmime-master/tests/parser/charsetTestSuites.hpp
@@ -0,0 +1,102 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+
+struct charsetTestSuiteStruct {
+
+ const char* fromCharset;
+ const char* toCharset;
+ const char* fromBytes;
+ const unsigned int fromLength;
+ const char* toBytes;
+ const unsigned int toLength;
+};
+
+
+static const charsetTestSuiteStruct charsetTestSuites[] = {
+
+ // Test data 1 (excerpt from http://www.gnu.org)
+ {
+ "gb2312", "utf-8",
+
+ "\xbb\xb6\xd3\xad\xc0\xb4\xb5\xbd\x20\x47\x4e\x55\x20\xb9\xa4\xb3"
+ "\xcc\xb5\xc4\xcd\xf8\xd2\xb3\xcb\xc5\xb7\xfe\xd6\xf7\xbb\xfa\x20"
+ "\x77\x77\x77\x2e\x67\x6e\x75\x2e\x6f\x72\x67\x20\xa1\xa3\x20\x47"
+ "\x4e\x55\x20\xb9\xa4\xb3\xcc\x20\xbf\xaa\xca\xbc\xec\xb6\xd2\xbb"
+ "\xbe\xc5\xb0\xcb\xcb\xc4\xc4\xea\xa3\xac\xd6\xbc\xd4\xda\xb7\xa2"
+ "\xd5\xb9\xd2\xbb\xb8\xf6\xc0\xe0\xcb\xc6\x20\x55\x6e\x69\x78\x20"
+ "\xa3\xac\xc7\xd2\xce\xaa\x20\xd7\xd4\xd3\xc9\xc8\xed\xbc\xfe\x20"
+ "\xb5\xc4\xcd\xea\xd5\xfb\xb2\xd9\xd7\xf7\xcf\xb5\xcd\xb3\xa3\xba"
+ "\x20\x47\x4e\x55\x20\xcf\xb5\xcd\xb3\xa1\xa3\xa3\xa8\x47\x4e\x55"
+ "\x20\xca\xc7\xd3\xc9\xa1\xb0\x47\x4e\x55\x27\x73\x20\x4e\x6f\x74"
+ "\x20\x55\x6e\x69\x78\xa1\xb1\xcb\xf9\xb5\xdd\xbb\xd8\xb6\xa8\xd2"
+ "\xe5\xb3\xf6\xb5\xc4\xca\xd7\xd7\xd6\xc4\xb8\xcb\xf5\xd0\xb4\xd3"
+ "\xef\xa3\xbb\xcb\xfc\xb5\xc4\xb7\xa2\xd2\xf4\xce\xaa\xa1\xb0\x67"
+ "\x75\x68\x2d\x4e\x45\x57\xa1\xb1\xa3\xa9\xa1\xa3\xb8\xf7\xd6\xd6"
+ "\xca\xb9\xd3\xc3\x20\x4c\x69\x6e\x75\x78\x20\xd7\xf7\xce\xaa\xc4"
+ "\xda\xba\xcb\xb5\xc4\x20\x47\x4e\x55\x20\xb2\xd9\xd7\xf7\xcf\xb5"
+ "\xcd\xb3\xd5\xfd\xb1\xbb\xb9\xe3\xb7\xba\xb5\xd8\xca\xb9\xd3\xc3"
+ "\xd6\xf8\xa3\xbb\xcb\xe4\xc8\xbb\xd5\xe2\xd0\xa9\xcf\xb5\xcd\xb3"
+ "\xcd\xa8\xb3\xa3\xb1\xbb\xb3\xc6\xd7\xf7\xce\xaa\xa1\xb0\x4c\x69"
+ "\x6e\x75\x78\xa1\xb1\xa3\xac\xb5\xab\xca\xc7\xcb\xfc\xc3\xc7\xd3"
+ "\xa6\xb8\xc3\xb8\xfc\xbe\xab\xc8\xb7\xb5\xd8\xb1\xbb\xb3\xc6\xce"
+ "\xaa\x20\x47\x4e\x55\x2f\x4c\x69\x6e\x75\x78\x20\xcf\xb5\xcd\xb3"
+ "\x20\xa1\xa3\x0a",
+ 0,
+
+ "\xe6\xac\xa2\xe8\xbf\x8e\xe6\x9d\xa5\xe5\x88\xb0\x20\x47\x4e\x55"
+ "\x20\xe5\xb7\xa5\xe7\xa8\x8b\xe7\x9a\x84\xe7\xbd\x91\xe9\xa1\xb5"
+ "\xe4\xbc\xba\xe6\x9c\x8d\xe4\xb8\xbb\xe6\x9c\xba\x20\x77\x77\x77"
+ "\x2e\x67\x6e\x75\x2e\x6f\x72\x67\x20\xe3\x80\x82\x20\x47\x4e\x55"
+ "\x20\xe5\xb7\xa5\xe7\xa8\x8b\x20\xe5\xbc\x80\xe5\xa7\x8b\xe6\x96"
+ "\xbc\xe4\xb8\x80\xe4\xb9\x9d\xe5\x85\xab\xe5\x9b\x9b\xe5\xb9\xb4"
+ "\xef\xbc\x8c\xe6\x97\xa8\xe5\x9c\xa8\xe5\x8f\x91\xe5\xb1\x95\xe4"
+ "\xb8\x80\xe4\xb8\xaa\xe7\xb1\xbb\xe4\xbc\xbc\x20\x55\x6e\x69\x78"
+ "\x20\xef\xbc\x8c\xe4\xb8\x94\xe4\xb8\xba\x20\xe8\x87\xaa\xe7\x94"
+ "\xb1\xe8\xbd\xaf\xe4\xbb\xb6\x20\xe7\x9a\x84\xe5\xae\x8c\xe6\x95"
+ "\xb4\xe6\x93\x8d\xe4\xbd\x9c\xe7\xb3\xbb\xe7\xbb\x9f\xef\xbc\x9a"
+ "\x20\x47\x4e\x55\x20\xe7\xb3\xbb\xe7\xbb\x9f\xe3\x80\x82\xef\xbc"
+ "\x88\x47\x4e\x55\x20\xe6\x98\xaf\xe7\x94\xb1\xe2\x80\x9c\x47\x4e"
+ "\x55\x27\x73\x20\x4e\x6f\x74\x20\x55\x6e\x69\x78\xe2\x80\x9d\xe6"
+ "\x89\x80\xe9\x80\x92\xe5\x9b\x9e\xe5\xae\x9a\xe4\xb9\x89\xe5\x87"
+ "\xba\xe7\x9a\x84\xe9\xa6\x96\xe5\xad\x97\xe6\xaf\x8d\xe7\xbc\xa9"
+ "\xe5\x86\x99\xe8\xaf\xad\xef\xbc\x9b\xe5\xae\x83\xe7\x9a\x84\xe5"
+ "\x8f\x91\xe9\x9f\xb3\xe4\xb8\xba\xe2\x80\x9c\x67\x75\x68\x2d\x4e"
+ "\x45\x57\xe2\x80\x9d\xef\xbc\x89\xe3\x80\x82\xe5\x90\x84\xe7\xa7"
+ "\x8d\xe4\xbd\xbf\xe7\x94\xa8\x20\x4c\x69\x6e\x75\x78\x20\xe4\xbd"
+ "\x9c\xe4\xb8\xba\xe5\x86\x85\xe6\xa0\xb8\xe7\x9a\x84\x20\x47\x4e"
+ "\x55\x20\xe6\x93\x8d\xe4\xbd\x9c\xe7\xb3\xbb\xe7\xbb\x9f\xe6\xad"
+ "\xa3\xe8\xa2\xab\xe5\xb9\xbf\xe6\xb3\x9b\xe5\x9c\xb0\xe4\xbd\xbf"
+ "\xe7\x94\xa8\xe8\x91\x97\xef\xbc\x9b\xe8\x99\xbd\xe7\x84\xb6\xe8"
+ "\xbf\x99\xe4\xba\x9b\xe7\xb3\xbb\xe7\xbb\x9f\xe9\x80\x9a\xe5\xb8"
+ "\xb8\xe8\xa2\xab\xe7\xa7\xb0\xe4\xbd\x9c\xe4\xb8\xba\xe2\x80\x9c"
+ "\x4c\x69\x6e\x75\x78\xe2\x80\x9d\xef\xbc\x8c\xe4\xbd\x86\xe6\x98"
+ "\xaf\xe5\xae\x83\xe4\xbb\xac\xe5\xba\x94\xe8\xaf\xa5\xe6\x9b\xb4"
+ "\xe7\xb2\xbe\xe7\xa1\xae\xe5\x9c\xb0\xe8\xa2\xab\xe7\xa7\xb0\xe4"
+ "\xb8\xba\x20\x47\x4e\x55\x2f\x4c\x69\x6e\x75\x78\x20\xe7\xb3\xbb"
+ "\xe7\xbb\x9f\x20\xe3\x80\x82\x0a",
+ 0
+ }
+};
+
+static const vmime::size_t charsetTestSuitesCount = sizeof(charsetTestSuites) / sizeof(charsetTestSuites[0]);
diff --git a/vmime-master/tests/parser/datetimeTest.cpp b/vmime-master/tests/parser/datetimeTest.cpp
new file mode 100644
index 0000000..61c8522
--- /dev/null
+++ b/vmime-master/tests/parser/datetimeTest.cpp
@@ -0,0 +1,123 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "tests/testUtils.hpp"
+
+
+VMIME_TEST_SUITE_BEGIN(datetimeTest)
+
+ VMIME_TEST_LIST_BEGIN
+ VMIME_TEST(testParse)
+ VMIME_TEST(testGenerate)
+ VMIME_TEST(testCompare)
+ VMIME_TEST_LIST_END
+
+
+ void testParse() {
+
+ struct datetimePair {
+ vmime::string parseBuffer;
+ vmime::datetime result;
+ };
+
+ // Here, we can't test all the possible structures for date/time,
+ // so we test some cases. Don't forget to add a new test case
+ // each time you encounter a bug in date/time parsing (after
+ // you have fixed it).
+ datetimePair pairs[] = {
+
+ { /* 1 */ "Mon, 8 Nov 2004 13:42:56 +0000 (GMT)",
+ vmime::datetime(2004, 11, 8, 13, 42, 56, vmime::datetime::GMT) },
+
+ { /* 2 */ "Sun, 7 Nov 2004 00:43:22 -0500 (EST)",
+ vmime::datetime(2004, 11, 7, 0, 43, 22, vmime::datetime::GMT_5) },
+
+ { /* 3 */ "Thu Nov 18 12:11:16 2004",
+ vmime::datetime(vmime::datetime::now().getYear(), 11, 18, 12, 11, 16, vmime::datetime::GMT) },
+
+ { /* 4 */ "Sat, 18, 2004 22:36:32 -0400",
+ vmime::datetime(2004, 1, 18, 22, 36, 32, vmime::datetime::GMT_4) },
+
+ { /* 5 */ "Mon Dec 13 21:57:18 2004",
+ vmime::datetime(vmime::datetime::now().getYear(), 12, 13, 21, 57, 18, vmime::datetime::GMT) },
+
+ { /* 6 */ "18 Nov 2004 21:44:54 +0300",
+ vmime::datetime(2004, 11, 18, 21, 44, 54, vmime::datetime::GMT3) }
+ };
+
+ for (unsigned int i = 0 ; i < sizeof(pairs) / sizeof(pairs[0]) ; ++i) {
+
+ vmime::datetime d;
+ d.parse(pairs[i].parseBuffer);
+
+ std::ostringstream oss;
+ oss << (i + 1);
+
+ VASSERT_EQ(oss.str(), pairs[i].result, d);
+ }
+ }
+
+ void testGenerate() {
+
+ vmime::datetime d1(2005, 7, 8, 4, 5, 6, 1 * 60 + 23);
+
+ VASSERT_EQ("1", "Fri, 8 Jul 2005 04:05:06 +0123", d1.generate());
+ }
+
+ void testCompare() {
+
+ // Date1 = Date2
+ vmime::datetime d1(2005, 4, 22, 14, 6, 0, vmime::datetime::GMT2);
+ vmime::datetime d2(2005, 4, 22, 10, 6, 0, vmime::datetime::GMT_2);
+
+ VASSERT_EQ("1.1", true, d1 == d2);
+ VASSERT_EQ("1.2", false, d1 != d2);
+ VASSERT_EQ("1.3", true, d1 <= d2);
+ VASSERT_EQ("1.4", false, d1 < d2);
+ VASSERT_EQ("1.5", true, d1 >= d2);
+ VASSERT_EQ("1.6", false, d1 > d2);
+
+ // Date1 < Date2
+ vmime::datetime d3(2005, 4, 22, 14, 6, 0);
+ vmime::datetime d4(2005, 4, 22, 15, 6, 0);
+
+ VASSERT_EQ("2.1", false, d3 == d4);
+ VASSERT_EQ("2.2", true, d3 != d4);
+ VASSERT_EQ("2.3", true, d3 <= d4);
+ VASSERT_EQ("2.4", true, d3 < d4);
+ VASSERT_EQ("2.5", false, d3 >= d4);
+ VASSERT_EQ("2.6", false, d3 > d4);
+
+ // Date1 > Date2
+ vmime::datetime d5(2005, 4, 22, 15, 6, 0);
+ vmime::datetime d6(2005, 4, 22, 14, 6, 0);
+
+ VASSERT_EQ("3.1", false, d5 == d6);
+ VASSERT_EQ("3.2", true, d5 != d6);
+ VASSERT_EQ("3.3", false, d5 <= d6);
+ VASSERT_EQ("3.4", false, d5 < d6);
+ VASSERT_EQ("3.5", true, d5 >= d6);
+ VASSERT_EQ("3.6", true, d5 > d6);
+ }
+
+VMIME_TEST_SUITE_END
diff --git a/vmime-master/tests/parser/dispositionTest.cpp b/vmime-master/tests/parser/dispositionTest.cpp
new file mode 100644
index 0000000..f51c51e
--- /dev/null
+++ b/vmime-master/tests/parser/dispositionTest.cpp
@@ -0,0 +1,150 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "tests/testUtils.hpp"
+
+
+VMIME_TEST_SUITE_BEGIN(dispositionTest)
+
+ VMIME_TEST_LIST_BEGIN
+ VMIME_TEST(testParse)
+ VMIME_TEST(testGenerate)
+ VMIME_TEST(testModifiers)
+ VMIME_TEST_LIST_END
+
+
+ void testParse() {
+
+ // disposition-mode ";" disposition-type
+ // [ "/" disposition-modifier *( "," disposition-modifier ) ]
+ //
+ // disposition-mode = action-mode "/" sending-mode
+
+ vmime::disposition disp1;
+ disp1.parse("mode");
+
+ VASSERT_EQ("1.1", "mode", disp1.getActionMode());
+ VASSERT_EQ("1.2", "", disp1.getSendingMode());
+ VASSERT_EQ("1.3", "", disp1.getType());
+ VASSERT_EQ("1.4", 0, static_cast <int>(disp1.getModifierList().size()));
+
+ vmime::disposition disp2;
+ disp2.parse("amode/smode");
+
+ VASSERT_EQ("2.1", "amode", disp2.getActionMode());
+ VASSERT_EQ("2.2", "smode", disp2.getSendingMode());
+ VASSERT_EQ("2.3", "", disp2.getType());
+ VASSERT_EQ("2.4", 0, static_cast <int>(disp2.getModifierList().size()));
+
+ vmime::disposition disp3;
+ disp3.parse("amode/smode;type");
+
+ VASSERT_EQ("3.1", "amode", disp3.getActionMode());
+ VASSERT_EQ("3.2", "smode", disp3.getSendingMode());
+ VASSERT_EQ("3.3", "type", disp3.getType());
+ VASSERT_EQ("3.4", 0, static_cast <int>(disp3.getModifierList().size()));
+
+ vmime::disposition disp4;
+ disp4.parse("amode/smode;type/modif");
+
+ VASSERT_EQ("4.1", "amode", disp4.getActionMode());
+ VASSERT_EQ("4.2", "smode", disp4.getSendingMode());
+ VASSERT_EQ("4.3", "type", disp4.getType());
+ VASSERT_EQ("4.4", 1, static_cast <int>(disp4.getModifierList().size()));
+ VASSERT_EQ("4.5", "modif", disp4.getModifierList()[0]);
+
+ vmime::disposition disp5;
+ disp5.parse("amode/smode;type/modif1,modif2");
+
+ VASSERT_EQ("5.1", "amode", disp5.getActionMode());
+ VASSERT_EQ("5.2", "smode", disp5.getSendingMode());
+ VASSERT_EQ("5.3", "type", disp5.getType());
+ VASSERT_EQ("5.4", 2, static_cast <int>(disp5.getModifierList().size()));
+ VASSERT_EQ("5.5", "modif1", disp5.getModifierList()[0]);
+ VASSERT_EQ("5.6", "modif2", disp5.getModifierList()[1]);
+ }
+
+ void testGenerate() {
+
+ vmime::disposition disp;
+
+ VASSERT_EQ("1", "automatic-action/MDN-sent-automatically;displayed", disp.generate());
+
+ disp.setActionMode("amode");
+
+ VASSERT_EQ("2", "amode/MDN-sent-automatically;displayed", disp.generate());
+
+ disp.setActionMode("amode");
+ disp.setSendingMode("smode");
+
+ VASSERT_EQ("3", "amode/smode;displayed", disp.generate());
+
+ disp.setType("type");
+
+ VASSERT_EQ("4", "amode/smode;type", disp.generate());
+
+ disp.addModifier("modif1");
+
+ VASSERT_EQ("5", "amode/smode;type/modif1", disp.generate());
+
+ disp.addModifier("modif2");
+
+ VASSERT_EQ("6", "amode/smode;type/modif1,modif2", disp.generate());
+ }
+
+ void testModifiers() {
+
+ vmime::disposition disp1;
+
+ VASSERT_EQ("1", false, disp1.hasModifier("foo"));
+ VASSERT_EQ("2", 0, static_cast <int>(disp1.getModifierList().size()));
+
+ disp1.addModifier("bar");
+
+ VASSERT_EQ("3", false, disp1.hasModifier("foo"));
+ VASSERT_EQ("4", true, disp1.hasModifier("bar"));
+ VASSERT_EQ("5", 1, static_cast <int>(disp1.getModifierList().size()));
+
+ disp1.addModifier("plop");
+
+ VASSERT_EQ("6", false, disp1.hasModifier("foo"));
+ VASSERT_EQ("7", true, disp1.hasModifier("bar"));
+ VASSERT_EQ("8", true, disp1.hasModifier("plop"));
+ VASSERT_EQ("9", 2, static_cast <int>(disp1.getModifierList().size()));
+
+ disp1.removeModifier("bar");
+
+ VASSERT_EQ("10", false, disp1.hasModifier("foo"));
+ VASSERT_EQ("11", false, disp1.hasModifier("bar"));
+ VASSERT_EQ("12", true, disp1.hasModifier("plop"));
+ VASSERT_EQ("13", 1, static_cast <int>(disp1.getModifierList().size()));
+
+ disp1.removeModifier("PlOp");
+
+ VASSERT_EQ("14", false, disp1.hasModifier("foo"));
+ VASSERT_EQ("15", false, disp1.hasModifier("bar"));
+ VASSERT_EQ("16", false, disp1.hasModifier("plop"));
+ VASSERT_EQ("17", 0, static_cast <int>(disp1.getModifierList().size()));
+ }
+
+VMIME_TEST_SUITE_END
diff --git a/vmime-master/tests/parser/emailAddressTest.cpp b/vmime-master/tests/parser/emailAddressTest.cpp
new file mode 100644
index 0000000..f2a7070
--- /dev/null
+++ b/vmime-master/tests/parser/emailAddressTest.cpp
@@ -0,0 +1,281 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "tests/testUtils.hpp"
+
+#include "vmime/platform.hpp"
+
+#include <locale>
+#include <clocale>
+
+
+VMIME_TEST_SUITE_BEGIN(emailAddressTest)
+
+ VMIME_TEST_LIST_BEGIN
+ VMIME_TEST(testParseASCII)
+ VMIME_TEST(testParseEAI)
+ VMIME_TEST(testParseInvalid)
+ VMIME_TEST(testGenerateASCII)
+ VMIME_TEST(testGenerateEAI)
+ VMIME_TEST(testParseSpecialChars)
+ VMIME_TEST(testParseCommentInLocalPart)
+ VMIME_TEST(testParseCommentInDomainPart)
+ VMIME_TEST(testParseRFC2047EncodedLocalPart)
+ VMIME_TEST(testGenerateSpecialChars)
+ VMIME_TEST_LIST_END
+
+
+ void setUp() {
+
+ // Set the global C and C++ locale to the user-configured locale.
+ // The locale should use UTF-8 encoding for these tests to run successfully.
+ try {
+ std::locale::global(std::locale(""));
+ } catch (std::exception &) {
+ std::setlocale(LC_ALL, "");
+ }
+ }
+
+ void tearDown() {
+
+ // Restore default locale
+ std::locale::global(std::locale("C"));
+ }
+
+
+ void testParseASCII() {
+
+ vmime::emailAddress eml1("local@domain");
+ VASSERT_EQ("1/local", "local", eml1.getLocalName());
+ VASSERT_EQ("1/domain", "domain", eml1.getDomainName());
+
+ // When not specified, domain should be local host name
+ vmime::emailAddress eml2("local");
+ VASSERT_EQ("2/local", "local", eml2.getLocalName());
+ VASSERT_EQ("2/domain", vmime::platform::getHandler()->getHostName(), eml2.getDomainName());
+ }
+
+ void testParseEAI() {
+
+ // Examples taken from Wikipedia (http://en.wikipedia.org/wiki/Email_address)
+
+ // Latin Alphabet (with diacritics):
+ vmime::emailAddress eml1("Pelé@example.com");
+ VASSERT_EQ("1/local", "Pelé", eml1.getLocalName());
+ VASSERT_EQ("1/domain", "example.com", eml1.getDomainName());
+
+ // Greek Alphabet
+ vmime::emailAddress eml2("δοκιμή@παράδειγμα.δοκιμή");
+ VASSERT_EQ("2/local", "δοκιμή", eml2.getLocalName());
+ VASSERT_EQ("2/domain", "παράδειγμα.δοκιμή", eml2.getDomainName());
+
+ // Japanese Characters
+ vmime::emailAddress eml3("甲斐@黒川.日本");
+ VASSERT_EQ("3/local", "甲斐", eml3.getLocalName());
+ VASSERT_EQ("3/domain", "黒川.日本", eml3.getDomainName());
+
+ // Cyrillic Characters
+ vmime::emailAddress eml4("чебурашка@ящик-с-апельсинами.рф");
+ VASSERT_EQ("4/local", "чебурашка", eml4.getLocalName());
+ VASSERT_EQ("4/domain", "ящик-с-апельсинами.рф", eml4.getDomainName());
+ }
+
+ void testParseInvalid() {
+
+ // Only one @ is allowed outside quotation marks
+ vmime::emailAddress eml1("local@part@domain");
+ VASSERT_EQ("1/local", "local", eml1.getLocalName());
+ VASSERT_EQ("1/domain", "part@domain", eml1.getDomainName());
+
+ // Quoted strings must be dot separated, or the only element making up
+ // the local-part: should be parsed correctly, but it still represents
+ // an invalid email address
+ vmime::emailAddress eml2("Just\"not\"right@example.com");
+ VASSERT_EQ("2/local", "Just\"not\"right", eml2.getLocalName());
+ VASSERT_EQ("2/domain", "example.com", eml2.getDomainName());
+
+ // An @ character must separate the local and domain parts
+ vmime::emailAddress eml3("Abc.example.com");
+ VASSERT_EQ("3/local", "Abc.example.com", eml3.getLocalName());
+ VASSERT_EQ("3/domain", vmime::platform::getHandler()->getHostName(), eml3.getDomainName());
+
+ // Whitespace must be escaped
+ vmime::emailAddress eml4("local part@domain");
+ VASSERT_EQ("4/local", "local", eml4.getLocalName());
+ VASSERT_EQ("4/domain", vmime::platform::getHandler()->getHostName(), eml4.getDomainName());
+
+ vmime::emailAddress eml5("this\\ still\\\"not\\\\allowed@example.com");
+ VASSERT_EQ("5/local", "this\\", eml5.getLocalName());
+ VASSERT_EQ("5/domain", vmime::platform::getHandler()->getHostName(), eml5.getDomainName());
+ }
+
+ void testParseSpecialChars() {
+
+ // Examples taken from Wikipedia (http://en.wikipedia.org/wiki/Email_address)
+
+ vmime::emailAddress eml1("\" \"@example.org");
+ VASSERT_EQ("1/local", " ", eml1.getLocalName());
+ VASSERT_EQ("1/domain", "example.org", eml1.getDomainName());
+
+ vmime::emailAddress eml2("\"()<>[]:,;@\\\\\\\"!#$%&'*+-/=?^_`{}| ~.a\"@example.org");
+ VASSERT_EQ("2/local", "()<>[]:,;@\\\"!#$%&'*+-/=?^_`{}| ~.a", eml2.getLocalName());
+ VASSERT_EQ("3/domain", "example.org", eml2.getDomainName());
+
+ vmime::emailAddress eml3("!#$%&'*+-/=?^_`{}|~@example.org");
+ VASSERT_EQ("3/local", "!#$%&'*+-/=?^_`{}|~", eml3.getLocalName());
+ VASSERT_EQ("3/domain", "example.org", eml3.getDomainName());
+
+ vmime::emailAddress eml4("!#$%&'*+-/=?^_`{}|~@example.org");
+ VASSERT_EQ("4/local", "!#$%&'*+-/=?^_`{}|~", eml4.getLocalName());
+ VASSERT_EQ("4/domain", "example.org", eml4.getDomainName());
+
+ vmime::emailAddress eml5("\"very.unusual.@.unusual.com\"@example.com");
+ VASSERT_EQ("5/local", "very.unusual.@.unusual.com", eml5.getLocalName());
+ VASSERT_EQ("5/domain", "example.com", eml5.getDomainName());
+
+ vmime::emailAddress eml6("\"very.(),:;<>[]\\\".VERY.\\\"very@\\\\ \\\"very\\\".unusual\"@strange.example.com");
+ VASSERT_EQ("6/local", "very.(),:;<>[]\".VERY.\"very@\\ \"very\".unusual", eml6.getLocalName());
+ VASSERT_EQ("6/domain", "strange.example.com", eml6.getDomainName());
+ }
+
+ void testParseCommentInLocalPart() {
+
+ vmime::emailAddress eml1("john.smith(comment)@example.com");
+ VASSERT_EQ("1/local", "john.smith", eml1.getLocalName());
+ VASSERT_EQ("1/domain", "example.com", eml1.getDomainName());
+
+ vmime::emailAddress eml2("(comment)john.smith@example.com");
+ VASSERT_EQ("2/local", "john.smith", eml2.getLocalName());
+ VASSERT_EQ("2/domain", "example.com", eml2.getDomainName());
+
+ vmime::emailAddress eml3("(comment (comment in comment))john.smith@example.com");
+ VASSERT_EQ("3/local", "john.smith", eml3.getLocalName());
+ VASSERT_EQ("3/domain", "example.com", eml3.getDomainName());
+
+ vmime::emailAddress eml4("(comment \\) end comment)john.smith@example.com");
+ VASSERT_EQ("4/local", "john.smith", eml4.getLocalName());
+ VASSERT_EQ("4/domain", "example.com", eml4.getDomainName());
+ }
+
+ void testParseCommentInDomainPart() {
+
+ vmime::emailAddress eml1("john.smith@(comment)example.com");
+ VASSERT_EQ("1/local", "john.smith", eml1.getLocalName());
+ VASSERT_EQ("1/domain", "example.com", eml1.getDomainName());
+
+ vmime::emailAddress eml2("john.smith@example.com(comment)");
+ VASSERT_EQ("2/local", "john.smith", eml2.getLocalName());
+ VASSERT_EQ("2/domain", "example.com", eml2.getDomainName());
+
+ vmime::emailAddress eml3("john.smith@(comment (comment in comment))example.com");
+ VASSERT_EQ("3/local", "john.smith", eml3.getLocalName());
+ VASSERT_EQ("3/domain", "example.com", eml3.getDomainName());
+
+ vmime::emailAddress eml4("john.smith@(comment \\) end comment)example.com");
+ VASSERT_EQ("4/local", "john.smith", eml4.getLocalName());
+ VASSERT_EQ("4/domain", "example.com", eml4.getDomainName());
+ }
+
+ void testParseRFC2047EncodedLocalPart() {
+
+ vmime::emailAddress eml1("=?utf-8?Q?Pel=C3=A9?=@example.com");
+ VASSERT_EQ("1/local", "Pelé", eml1.getLocalName());
+ VASSERT_EQ("1/domain", "example.com", eml1.getDomainName());
+
+ vmime::emailAddress eml2("=?utf-8?B?55Sy5paQ?=@xn--5rtw95l.xn--wgv71a");
+ VASSERT_EQ("2/local", "甲斐", eml2.getLocalName());
+ VASSERT_EQ("2/domain", "黒川.日本", eml2.getDomainName());
+
+ vmime::emailAddress eml3("=?utf-8?B?55Sy5paQ?=@xn--5rtw95l.com");
+ VASSERT_EQ("3/local", "甲斐", eml3.getLocalName());
+ VASSERT_EQ("3/domain", "黒川.com", eml3.getDomainName());
+ }
+
+ void testGenerateASCII() {
+
+ VASSERT_EQ(
+ "email 1", "local@domain",
+ vmime::emailAddress("local", "domain").generate()
+ );
+ VASSERT_EQ(
+ "email 2", "=?utf-8?Q?Pel=C3=A9?=@example.com",
+ vmime::emailAddress("Pelé", "example.com").generate()
+ );
+ VASSERT_EQ(
+ "email 3", "=?utf-8?B?55Sy5paQ?=@xn--5rtw95l.xn--wgv71a",
+ vmime::emailAddress("甲斐", "黒川.日本").generate()
+ );
+ VASSERT_EQ(
+ "email 4", "mailtest@xn--r8jz45g.xn--zckzah",
+ vmime::emailAddress("mailtest", "例え.テスト").generate()
+ );
+ VASSERT_EQ(
+ "email 5", "mailtest@xn--mgbh0fb.xn--kgbechtv",
+ vmime::emailAddress("mailtest", "مثال.إختبار").generate()
+ );
+ }
+
+ void testGenerateEAI() {
+
+ vmime::generationContext ctx(vmime::generationContext::getDefaultContext());
+ ctx.setInternationalizedEmailSupport(true);
+
+ vmime::generationContext::switcher <vmime::generationContext> contextSwitcher(ctx);
+
+ VASSERT_EQ(
+ "email 1", "Pelé@example.com",
+ vmime::emailAddress("Pelé", "example.com").generate()
+ );
+ VASSERT_EQ(
+ "email 2", "δοκιμή@παράδειγμα.δοκιμή",
+ vmime::emailAddress("δοκιμή", "παράδειγμα.δοκιμή").generate()
+ );
+ VASSERT_EQ(
+ "email 3", "甲斐@黒川.日本",
+ vmime::emailAddress("甲斐", "黒川.日本").generate()
+ );
+ VASSERT_EQ(
+ "email 4", "чебурашка@ящик-с-апельсинами.рф",
+ vmime::emailAddress("чебурашка", "ящик-с-апельсинами.рф").generate()
+ );
+ }
+
+ void testGenerateSpecialChars() {
+
+ VASSERT_EQ(
+ "email 1", "\"very.unusual.@.unusual.com\"@example.com",
+ vmime::emailAddress("very.unusual.@.unusual.com", "example.com").generate()
+ );
+
+ VASSERT_EQ(
+ "email 2", "\"very.(),:;<>[]\\\".VERY.\\\"very@\\\\ \\\"very\\\".unusual\"@strange.example.com",
+ vmime::emailAddress("very.(),:;<>[]\".VERY.\"very@\\ \"very\".unusual", "strange.example.com").generate()
+ );
+
+ VASSERT_EQ(
+ "email 3", "\" \"@example.com",
+ vmime::emailAddress(" ", "example.com").generate()
+ );
+ }
+
+VMIME_TEST_SUITE_END
diff --git a/vmime-master/tests/parser/emptyContentHandlerTest.cpp b/vmime-master/tests/parser/emptyContentHandlerTest.cpp
new file mode 100644
index 0000000..43cd8c2
--- /dev/null
+++ b/vmime-master/tests/parser/emptyContentHandlerTest.cpp
@@ -0,0 +1,99 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "tests/testUtils.hpp"
+
+#include "vmime/utility/outputStreamAdapter.hpp"
+
+
+VMIME_TEST_SUITE_BEGIN(emptyContentHandlerTest)
+
+ VMIME_TEST_LIST_BEGIN
+ VMIME_TEST(testIsEmpty)
+ VMIME_TEST(testGetLength)
+ VMIME_TEST(testIsEncoded)
+ VMIME_TEST(testExtract)
+ VMIME_TEST(testExtractRaw)
+ VMIME_TEST(testGenerate)
+ VMIME_TEST_LIST_END
+
+
+ void testIsEmpty() {
+
+ vmime::emptyContentHandler cth;
+
+ VASSERT_TRUE("empty", cth.isEmpty());
+ }
+
+ void testGetLength() {
+
+ vmime::emptyContentHandler cth;
+
+ VASSERT_EQ("length", 0, cth.getLength());
+ }
+
+ void testIsEncoded() {
+
+ vmime::emptyContentHandler cth;
+
+ VASSERT_FALSE("encoded", cth.isEncoded());
+ VASSERT_EQ("encoding", vmime::contentHandler::NO_ENCODING, cth.getEncoding());
+ }
+
+ void testExtract() {
+
+ vmime::emptyContentHandler cth;
+
+ std::ostringstream oss;
+ vmime::utility::outputStreamAdapter osa(oss);
+
+ cth.extract(osa);
+
+ VASSERT_EQ("extract", "", oss.str());
+ }
+
+ void testExtractRaw() {
+
+ vmime::emptyContentHandler cth;
+
+ std::ostringstream oss;
+ vmime::utility::outputStreamAdapter osa(oss);
+
+ cth.extractRaw(osa);
+
+ VASSERT_EQ("extractRaw", "", oss.str());
+ }
+
+ void testGenerate() {
+
+ vmime::emptyContentHandler cth;
+
+ std::ostringstream oss;
+ vmime::utility::outputStreamAdapter osa(oss);
+
+ cth.generate(osa, vmime::encoding("base64"));
+
+ VASSERT_EQ("generate", "", oss.str());
+ }
+
+VMIME_TEST_SUITE_END
diff --git a/vmime-master/tests/parser/fileContentHandlerTest.cpp b/vmime-master/tests/parser/fileContentHandlerTest.cpp
new file mode 100644
index 0000000..e979b52
--- /dev/null
+++ b/vmime-master/tests/parser/fileContentHandlerTest.cpp
@@ -0,0 +1,134 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "tests/testUtils.hpp"
+
+#include "vmime/utility/outputStreamAdapter.hpp"
+
+
+VMIME_TEST_SUITE_BEGIN(fileContentHandlerTest)
+
+ VMIME_TEST_LIST_BEGIN
+ VMIME_TEST(testIsEmpty)
+ VMIME_TEST(testGetLength)
+ VMIME_TEST(testIsEncoded)
+ VMIME_TEST(testExtract)
+ VMIME_TEST(testExtractRaw)
+ VMIME_TEST(testGenerate)
+ VMIME_TEST_LIST_END
+
+
+ vmime::shared_ptr <vmime::utility::file> testFile;
+ vmime::string testDataEncoded, testDataDecoded;
+
+
+ void setUp() {
+
+ testDataDecoded = "ABCDEFGHIJKLMNOPQRSTUVWXYZ \x12\x34\x56\x78\x90 abcdefghijklmnopqrstuvwxyz0123456789";
+ testDataEncoded = "QUJDREVGR0hJSktMTU5PUFFSU1RVVldYWVogEjRWeJAgYWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXowMTIzNDU2Nzg5";
+
+ std::ostringstream testFilePath;
+ testFilePath << "/tmp/vmime_test_" << (rand() % 999999999);
+
+ vmime::shared_ptr <vmime::utility::fileSystemFactory> fsf =
+ vmime::platform::getHandler()->getFileSystemFactory();
+
+ testFile = fsf->create(fsf->stringToPath(testFilePath.str()));
+ testFile->createFile();
+ testFile->getFileWriter()->getOutputStream()->write(testDataEncoded.data(), testDataEncoded.length());
+ }
+
+ void tearDown() {
+
+ testFile->remove();
+ testFile = vmime::null;
+ }
+
+
+ void testIsEmpty() {
+
+ vmime::fileContentHandler cth;
+
+ VASSERT_TRUE("empty", cth.isEmpty());
+ }
+
+ void testGetLength() {
+
+ vmime::fileContentHandler cth(testFile);
+
+ VASSERT_FALSE("empty", cth.isEmpty());
+ VASSERT_EQ("length", testDataEncoded.length(), cth.getLength());
+ }
+
+ void testIsEncoded() {
+
+ vmime::fileContentHandler cth(testFile, vmime::encoding("base64"));
+
+ VASSERT_TRUE("encoded", cth.isEncoded());
+ VASSERT_EQ("encoding", "base64", cth.getEncoding().generate());
+ }
+
+ void testExtract() {
+
+ vmime::fileContentHandler cth(testFile, vmime::encoding("base64"));
+
+ std::ostringstream oss;
+ vmime::utility::outputStreamAdapter osa(oss);
+
+ cth.extract(osa);
+
+ // Data should be decoded from B64
+ VASSERT_EQ("extract", testDataDecoded, oss.str());
+ }
+
+ void testExtractRaw() {
+
+ vmime::fileContentHandler cth(testFile, vmime::encoding("base64"));
+
+ std::ostringstream oss;
+ vmime::utility::outputStreamAdapter osa(oss);
+
+ cth.extractRaw(osa);
+
+ // Data should not be decoded
+ VASSERT_EQ("extractRaw", testDataEncoded, oss.str());
+ }
+
+ void testGenerate() {
+
+ vmime::fileContentHandler cth(testFile, vmime::encoding("base64"));
+
+ std::ostringstream oss;
+ vmime::utility::outputStreamAdapter osa(oss);
+
+ cth.generate(osa, vmime::encoding("quoted-printable"));
+
+ // Data should be reencoded from B64 to QP
+ VASSERT_EQ(
+ "generate",
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZ =124Vx=90 abcdefghijklmnopqrstuvwxyz0123456789",
+ oss.str()
+ );
+ }
+
+VMIME_TEST_SUITE_END
diff --git a/vmime-master/tests/parser/headerFieldTest.cpp b/vmime-master/tests/parser/headerFieldTest.cpp
new file mode 100644
index 0000000..78d0480
--- /dev/null
+++ b/vmime-master/tests/parser/headerFieldTest.cpp
@@ -0,0 +1,112 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "tests/testUtils.hpp"
+
+
+VMIME_TEST_SUITE_BEGIN(headerFieldTest)
+
+ VMIME_TEST_LIST_BEGIN
+ VMIME_TEST(testBadValueType)
+ VMIME_TEST(testValueOnNextLine)
+ VMIME_TEST(testStripSpacesAtEnd)
+ VMIME_TEST(testValueWithEmptyLine)
+ VMIME_TEST_LIST_END
+
+
+ void testBadValueType() {
+
+ vmime::shared_ptr <vmime::headerFieldFactory> hfactory =
+ vmime::headerFieldFactory::getInstance();
+
+ // "To" header field accepts values of type "addressList"
+ vmime::shared_ptr <vmime::headerField> to = hfactory->create(vmime::fields::TO);
+
+ VASSERT_THROW(
+ "to",
+ to->setValue(vmime::mailbox("email@vmime.org")),
+ vmime::exceptions::bad_field_value_type
+ );
+
+ // Unregistered header field accepts any value type
+ vmime::shared_ptr <vmime::headerField> custom = hfactory->create("X-MyCustomHeader");
+
+ VASSERT_NO_THROW(
+ "custom/1",
+ custom->setValue(vmime::mailbox("email@vmime.org"))
+ );
+ VASSERT_NO_THROW(
+ "custom/2",
+ custom->setValue(vmime::text("field value text"))
+ );
+ }
+
+ void testValueOnNextLine() {
+
+ vmime::parsingContext ctx;
+
+ const vmime::string buffer = "Field: \r\n\tfield data";
+
+ vmime::shared_ptr <vmime::headerField> hfield =
+ vmime::headerField::parseNext(ctx, buffer, 0, buffer.size());
+
+ vmime::shared_ptr <vmime::text> hvalue =
+ hfield->getValue <vmime::text>();
+
+ VASSERT_EQ("Field name", "Field", hfield->getName());
+ VASSERT_EQ("Field value", "field data", hvalue->getWholeBuffer());
+ }
+
+ void testStripSpacesAtEnd() {
+
+ vmime::parsingContext ctx;
+
+ const vmime::string buffer = "Field: \r\n\tfield data ";
+
+ vmime::shared_ptr <vmime::headerField> hfield =
+ vmime::headerField::parseNext(ctx, buffer, 0, buffer.size());
+
+ vmime::shared_ptr <vmime::text> hvalue =
+ hfield->getValue <vmime::text>();
+
+ VASSERT_EQ("Field name", "Field", hfield->getName());
+ VASSERT_EQ("Field value", toHex("field data"), toHex(hvalue->getWholeBuffer()));
+ }
+
+ void testValueWithEmptyLine() {
+
+ vmime::parsingContext ctx;
+
+ const vmime::string buffer = "Field: \r\n\tdata1\r\n\tdata2\r\n\t\r\n\tdata3";
+
+ vmime::shared_ptr <vmime::headerField> hfield =
+ vmime::headerField::parseNext(ctx, buffer, 0, buffer.size());
+
+ vmime::shared_ptr <vmime::text> hvalue =
+ hfield->getValue <vmime::text>();
+
+ VASSERT_EQ("Field name", "Field", hfield->getName());
+ VASSERT_EQ("Field value", "data1 data2 data3", hvalue->getWholeBuffer());
+ }
+
+VMIME_TEST_SUITE_END
diff --git a/vmime-master/tests/parser/headerTest.cpp b/vmime-master/tests/parser/headerTest.cpp
new file mode 100644
index 0000000..839acee
--- /dev/null
+++ b/vmime-master/tests/parser/headerTest.cpp
@@ -0,0 +1,375 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "tests/testUtils.hpp"
+
+
+VMIME_TEST_SUITE_BEGIN(headerTest)
+
+ VMIME_TEST_LIST_BEGIN
+ VMIME_TEST(testHas1)
+ VMIME_TEST(testHas2)
+
+ VMIME_TEST(testAppend1)
+ VMIME_TEST(testAppend2)
+
+ VMIME_TEST(testInsertFieldBefore1)
+ VMIME_TEST(testInsertFieldBefore2)
+
+ VMIME_TEST(testInsertFieldAfter1)
+ VMIME_TEST(testInsertFieldAfter2)
+
+ VMIME_TEST(testReplaceField)
+
+ VMIME_TEST(testRemoveField1)
+ VMIME_TEST(testRemoveField2)
+
+ VMIME_TEST(testRemoveAllFields)
+
+ VMIME_TEST(testgetFieldCount)
+
+ VMIME_TEST(testIsEmpty1)
+ VMIME_TEST(testIsEmpty2)
+
+ VMIME_TEST(testGetFieldAt)
+
+ VMIME_TEST(testGetFieldList1)
+ VMIME_TEST(testGetFieldList2)
+
+ VMIME_TEST(testFind1)
+
+ VMIME_TEST(testFindAllFields1)
+ VMIME_TEST(testFindAllFields2)
+ VMIME_TEST(testFindAllFields3)
+ VMIME_TEST_LIST_END
+
+
+ static const std::string getFieldValue(const vmime::headerField& field) {
+
+ std::ostringstream oss;
+ vmime::utility::outputStreamAdapter voss(oss);
+ field.generate(voss);
+
+ return oss.str();
+ }
+
+ // has function tests
+ void testHas1() {
+
+ vmime::header hdr;
+ hdr.parse("From: x\r\nTo: y\r\nTo: z\r\n");
+
+ bool res = hdr.hasField("Z");
+
+ VASSERT_EQ("Value", false, res);
+ }
+
+ void testHas2() {
+
+ vmime::header hdr;
+ hdr.parse("X: x\r\nTo: y\r\nTo: z\r\n");
+
+ bool res = hdr.hasField("To");
+
+ VASSERT_EQ("Value", true, res);
+ }
+
+ // appendField function tests
+ void testAppend1() {
+
+ vmime::header hdr;
+ hdr.parse("");
+
+ vmime::shared_ptr <vmime::headerField> hf = vmime::headerFieldFactory::getInstance()->create("A", "a");
+ hdr.appendField(hf);
+
+ std::vector <vmime::shared_ptr <vmime::headerField> > res = hdr.getFieldList();
+
+ VASSERT_EQ("Count", static_cast <unsigned int>(1), res.size());
+ VASSERT_EQ("First value", "A: a", headerTest::getFieldValue(*res[0]));
+ }
+
+ void testAppend2() {
+
+ vmime::header hdr;
+ hdr.parse("A: a\r\n");
+
+ vmime::shared_ptr <vmime::headerField> hf = vmime::headerFieldFactory::getInstance()->create("B", "b");
+ hdr.appendField(hf);
+
+ std::vector <vmime::shared_ptr <vmime::headerField> > res = hdr.getFieldList();
+
+ VASSERT_EQ("Count", static_cast <unsigned int>(2), res.size());
+ VASSERT_EQ("First value", "A: a", headerTest::getFieldValue(*res[0]));
+ VASSERT_EQ("Second value", "B: b", headerTest::getFieldValue(*res[1]));
+ }
+
+ // insertFieldBefore
+ void testInsertFieldBefore1() {
+
+ vmime::header hdr;
+ hdr.parse("A: a\r\nC: c\r\n");
+
+ vmime::shared_ptr <vmime::headerField> hf = vmime::headerFieldFactory::getInstance()->create("B", "b");
+ hdr.insertFieldBefore(hdr.getField("C"), hf);
+
+ std::vector <vmime::shared_ptr <vmime::headerField> > res = hdr.getFieldList();
+
+ VASSERT_EQ("Count", static_cast <unsigned int>(3), res.size());
+ VASSERT_EQ("First value", "A: a", headerTest::getFieldValue(*res[0]));
+ VASSERT_EQ("Second value", "B: b", headerTest::getFieldValue(*res[1]));
+ VASSERT_EQ("Third value", "C: c", headerTest::getFieldValue(*res[2]));
+ }
+
+ void testInsertFieldBefore2() {
+
+ vmime::header hdr;
+ hdr.parse("A: a\r\nC: c\r\n");
+
+ vmime::shared_ptr <vmime::headerField> hf = vmime::headerFieldFactory::getInstance()->create("B", "b");
+ hdr.insertFieldBefore(1, hf);
+
+ std::vector <vmime::shared_ptr <vmime::headerField> > res = hdr.getFieldList();
+
+ VASSERT_EQ("Count", static_cast <unsigned int>(3), res.size());
+ VASSERT_EQ("First value", "A: a", headerTest::getFieldValue(*res[0]));
+ VASSERT_EQ("Second value", "B: b", headerTest::getFieldValue(*res[1]));
+ VASSERT_EQ("Third value", "C: c", headerTest::getFieldValue(*res[2]));
+ }
+
+ // insertFieldAfter
+ void testInsertFieldAfter1() {
+
+ vmime::header hdr;
+ hdr.parse("A: a\r\nC: c\r\n");
+
+ vmime::shared_ptr <vmime::headerField> hf = vmime::headerFieldFactory::getInstance()->create("B", "b");
+ hdr.insertFieldAfter(hdr.getField("A"), hf);
+
+ std::vector <vmime::shared_ptr <vmime::headerField> > res = hdr.getFieldList();
+
+ VASSERT_EQ("Count", static_cast <unsigned int>(3), res.size());
+ VASSERT_EQ("First value", "A: a", headerTest::getFieldValue(*res[0]));
+ VASSERT_EQ("Second value", "B: b", headerTest::getFieldValue(*res[1]));
+ VASSERT_EQ("Third value", "C: c", headerTest::getFieldValue(*res[2]));
+ }
+
+ void testInsertFieldAfter2() {
+
+ vmime::header hdr;
+ hdr.parse("A: a\r\nC: c\r\n");
+
+ vmime::shared_ptr <vmime::headerField> hf = vmime::headerFieldFactory::getInstance()->create("B", "b");
+ hdr.insertFieldAfter(0, hf);
+
+ std::vector <vmime::shared_ptr <vmime::headerField> > res = hdr.getFieldList();
+
+ VASSERT_EQ("Count", static_cast <unsigned int>(3), res.size());
+ VASSERT_EQ("First value", "A: a", headerTest::getFieldValue(*res[0]));
+ VASSERT_EQ("Second value", "B: b", headerTest::getFieldValue(*res[1]));
+ VASSERT_EQ("Third value", "C: c", headerTest::getFieldValue(*res[2]));
+ }
+
+ // replaceField
+ void testReplaceField() {
+
+ vmime::header hdr;
+ hdr.parse("A: a\r\nB: b\r\nC: c\r\n");
+
+ vmime::shared_ptr <vmime::headerField> hf = vmime::headerFieldFactory::getInstance()->create("Z", "z");
+ hdr.replaceField(hdr.getField("B"), hf);
+
+ std::vector <vmime::shared_ptr <vmime::headerField> > res = hdr.getFieldList();
+
+ VASSERT_EQ("Count", static_cast <unsigned int>(3), res.size());
+ VASSERT_EQ("First value", "A: a", headerTest::getFieldValue(*res[0]));
+ VASSERT_EQ("Second value", "Z: z", headerTest::getFieldValue(*res[1]));
+ VASSERT_EQ("Third value", "C: c", headerTest::getFieldValue(*res[2]));
+ }
+
+ // removeField
+ void testRemoveField1() {
+
+ vmime::header hdr1, hdr2;
+ hdr1.parse("A: a\r\nB: b\r\nC: c\r\n");
+ hdr2.parse("A: a\r\nB: b\r\nC: c\r\n");
+
+ hdr1.removeField(hdr1.getField("B"));
+ hdr2.removeField(1);
+
+ std::vector <vmime::shared_ptr <vmime::headerField> > res1 = hdr1.getFieldList();
+
+ VASSERT_EQ("Count", static_cast <unsigned int>(2), res1.size());
+ VASSERT_EQ("First value", "A: a", headerTest::getFieldValue(*res1[0]));
+ VASSERT_EQ("Second value", "C: c", headerTest::getFieldValue(*res1[1]));
+
+ std::vector <vmime::shared_ptr <vmime::headerField> > res2 = hdr2.getFieldList();
+
+ VASSERT_EQ("Count", static_cast <unsigned int>(2), res2.size());
+ VASSERT_EQ("First value", "A: a", headerTest::getFieldValue(*res2[0]));
+ VASSERT_EQ("Second value", "C: c", headerTest::getFieldValue(*res2[1]));
+ }
+
+ void testRemoveField2() {
+
+ vmime::header hdr1, hdr2;
+ hdr1.parse("A: a\r\n");
+ hdr2.parse("A: a\r\n");
+
+ hdr1.removeField(hdr1.getField("A"));
+ hdr2.removeField(0);
+
+ std::vector <vmime::shared_ptr <vmime::headerField> > res1 = hdr1.getFieldList();
+ VASSERT_EQ("Count", static_cast <unsigned int>(0), res1.size());
+
+ std::vector <vmime::shared_ptr <vmime::headerField> > res2 = hdr2.getFieldList();
+ VASSERT_EQ("Count", static_cast <unsigned int>(0), res2.size());
+ }
+
+ // removeAllFields
+ void testRemoveAllFields() {
+
+ vmime::header hdr1, hdr2;
+ hdr1.parse("A: a\r\n");
+ hdr2.parse("A: a\r\nB: b\r\n");
+
+ hdr1.removeAllFields();
+ hdr2.removeAllFields();
+
+ std::vector <vmime::shared_ptr <vmime::headerField> > res1 = hdr1.getFieldList();
+ VASSERT_EQ("Count", static_cast <unsigned int>(0), res1.size());
+
+ std::vector <vmime::shared_ptr <vmime::headerField> > res2 = hdr2.getFieldList();
+ VASSERT_EQ("Count", static_cast <unsigned int>(0), res2.size());
+ }
+
+ // getFieldCount
+ void testgetFieldCount() {
+
+ vmime::header hdr;
+ hdr.parse("A: a\r\nB: b\r\nC: c\r\nD: d\r\n");
+
+ VASSERT_EQ("Value", 4, hdr.getFieldCount());
+ }
+
+ // isEmpty
+ void testIsEmpty1() {
+
+ vmime::header hdr;
+ hdr.parse("A: a\r\nB: b\r\nC: c\r\n");
+
+ VASSERT_EQ("Value", false, hdr.isEmpty());
+ }
+
+ void testIsEmpty2() {
+
+ vmime::header hdr;
+ hdr.parse("\r\n");
+
+ VASSERT_EQ("Value", true, hdr.isEmpty());
+ }
+
+ // getFieldAt
+ void testGetFieldAt() {
+
+ vmime::header hdr;
+ hdr.parse("B: b\r\nA: a\r\nC: c\r\n");
+
+ vmime::shared_ptr <vmime::headerField> res = hdr.getFieldAt(2);
+
+ VASSERT_EQ("Value", "C: c", getFieldValue(*res));
+ }
+
+ // getFieldList
+ void testGetFieldList1() {
+
+ vmime::header hdr;
+ hdr.parse("A: a\r\nB: b1\r\nC: c\r\nB: b2\r\n");
+
+ std::vector <vmime::shared_ptr <vmime::headerField> > res = hdr.getFieldList();
+
+ VASSERT_EQ("Count", static_cast <unsigned int>(4), res.size());
+ VASSERT_EQ("First value", "A: a", headerTest::getFieldValue(*res[0]));
+ VASSERT_EQ("Second value", "B: b1", headerTest::getFieldValue(*res[1]));
+ VASSERT_EQ("Third value", "C: c", headerTest::getFieldValue(*res[2]));
+ VASSERT_EQ("Thourth value", "B: b2", headerTest::getFieldValue(*res[3]));
+ }
+
+ void testGetFieldList2() {
+
+ vmime::header hdr;
+ hdr.parse("\r\n");
+
+ std::vector <vmime::shared_ptr <vmime::headerField> > res = hdr.getFieldList();
+
+ VASSERT_EQ("Count", static_cast <unsigned int>(0), res.size());
+ }
+
+ // find function tests
+ void testFind1() {
+
+ vmime::header hdr;
+ hdr.parse("A: a\r\nB: b\r\nC: c\r\nB: d\r\n");
+
+ vmime::shared_ptr <vmime::headerField> res = hdr.findField("B");
+
+ VASSERT_EQ("Value", "B: b", getFieldValue(*res));
+ }
+
+ // getAllByName function tests
+ void testFindAllFields1() {
+
+ vmime::header hdr;
+ hdr.parse("A: a1\nC: c1\n");
+
+ std::vector <vmime::shared_ptr <vmime::headerField> > res = hdr.findAllFields("B");
+
+ VASSERT_EQ("Count", static_cast <unsigned int>(0), res.size());
+ }
+
+ void testFindAllFields2() {
+
+ vmime::header hdr;
+ hdr.parse("A: a1\nB: b1\nB: b2\nC: c1\n");
+
+ std::vector <vmime::shared_ptr <vmime::headerField> > res = hdr.findAllFields("B");
+
+ VASSERT_EQ("Count", static_cast <unsigned int>(2), res.size());
+ VASSERT_EQ("First value", "B: b1", headerTest::getFieldValue(*res[0]));
+ VASSERT_EQ("Second value", "B: b2", headerTest::getFieldValue(*res[1]));
+ }
+
+ void testFindAllFields3() {
+
+ vmime::header hdr;
+ hdr.parse("A: a1\nB: b1\nB: b2\nC: c1\nC: c3\nC: c2\n");
+
+ std::vector <vmime::shared_ptr <vmime::headerField> > res = hdr.findAllFields("C");
+
+ VASSERT_EQ("Count", static_cast <unsigned int>(3), res.size());
+ VASSERT_EQ("First value", "C: c1", headerTest::getFieldValue(*res[0]));
+ VASSERT_EQ("Second value", "C: c3", headerTest::getFieldValue(*res[1]));
+ VASSERT_EQ("Second value", "C: c2", headerTest::getFieldValue(*res[2]));
+ }
+
+VMIME_TEST_SUITE_END
diff --git a/vmime-master/tests/parser/htmlTextPartTest.cpp b/vmime-master/tests/parser/htmlTextPartTest.cpp
new file mode 100644
index 0000000..6dfaaa0
--- /dev/null
+++ b/vmime-master/tests/parser/htmlTextPartTest.cpp
@@ -0,0 +1,241 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "tests/testUtils.hpp"
+#include "vmime/htmlTextPart.hpp"
+
+
+VMIME_TEST_SUITE_BEGIN(htmlTextPartTest)
+
+ VMIME_TEST_LIST_BEGIN
+ VMIME_TEST(testParseText)
+ VMIME_TEST(testParseEmbeddedObjectsCID)
+ VMIME_TEST(testParseEmbeddedObjectsLocation)
+ VMIME_TEST_LIST_END
+
+
+ static const vmime::string extractContent(
+ const vmime::shared_ptr <const vmime::contentHandler>& cth
+ ) {
+
+ std::ostringstream oss;
+ vmime::utility::outputStreamAdapter osa(oss);
+
+ cth->extract(osa);
+
+ return oss.str();
+ }
+
+
+ void testParseText() {
+
+ const vmime::string msgString = ""
+"MIME-Version: 1.0\r\n"
+"Content-Type: multipart/alternative; boundary=\"LEVEL1\"\r\n"
+"\r\n"
+"--LEVEL1\r\n"
+"Content-Type: text/plain; charset=\"x-ch1\"\r\n"
+"\r\n"
+"Plain text part\r\n"
+"--LEVEL1\r\n"
+"Content-Type: multipart/related; boundary=\"LEVEL2\"\r\n"
+"\r\n"
+"--LEVEL2\r\n"
+"Content-Type: text/html; charset=\"x-ch2\"\r\n"
+"\r\n"
+"<img src=\"cid:image@test\"/>\r\n"
+"--LEVEL2\r\n"
+"Content-Type: image/png; name=\"image.png\"\r\n"
+"Content-Disposition: inline; filename=\"image.png\"\r\n"
+"Content-ID: <image@test>\r\n"
+"\r\n"
+"Image\r\n"
+"--LEVEL2--\r\n"
+"\r\n"
+"--LEVEL1--\r\n"
+"";
+
+ vmime::shared_ptr <vmime::message> msg = vmime::make_shared <vmime::message>();
+ msg->parse(msgString);
+
+ // Sanity checks
+ VASSERT_EQ("part-count1", 2, msg->getBody()->getPartCount());
+ VASSERT_EQ("part-count2", 2, msg->getBody()->getPartAt(1)->getBody()->getPartCount());
+
+ vmime::htmlTextPart htmlPart;
+ htmlPart.parse(msg, msg->getBody()->getPartAt(1),
+ msg->getBody()->getPartAt(1)->getBody()->getPartAt(0));
+
+ VASSERT_EQ("plain", "Plain text part", extractContent(htmlPart.getPlainText()));
+ VASSERT_EQ("html", "<img src=\"cid:image@test\"/>", extractContent(htmlPart.getText()));
+
+ // Should return the charset of the HTML part
+ VASSERT_EQ("charset", "x-ch2", htmlPart.getCharset().generate());
+ }
+
+ /** Test parsing of embedded objects by CID (Content-Id).
+ */
+ void testParseEmbeddedObjectsCID() {
+
+ const vmime::string msgString = ""
+"MIME-Version: 1.0\r\n"
+"Content-Type: multipart/alternative; boundary=\"LEVEL1\"\r\n"
+"\r\n"
+"--LEVEL1\r\n"
+"Content-Type: text/plain; charset=\"x-ch1\"\r\n"
+"\r\n"
+"Plain text part\r\n"
+"--LEVEL1\r\n"
+"Content-Type: multipart/related; boundary=\"LEVEL2\"\r\n"
+"\r\n"
+"--LEVEL2\r\n" // one embedded object before...
+"Content-Type: image/png; name=\"image1.png\"\r\n"
+"Content-Disposition: inline; filename=\"image1.png\"\r\n"
+"Content-ID: <image1@test>\r\n"
+"\r\n"
+"Image1\r\n"
+"--LEVEL2\r\n" // ...the actual text part...
+"Content-Type: text/html; charset=\"x-ch2\"\r\n"
+"\r\n"
+"<img src=\"cid:image1@test\"/>\r\n"
+"<img src=\"CID:image2@test\"/>\r\n"
+"--LEVEL2\r\n" // ...and one after
+"Content-Type: image/jpeg; name=\"image2.jpg\"\r\n"
+"Content-Disposition: inline; filename=\"image2.jpg\"\r\n"
+"Content-ID: <image2@test>\r\n"
+"\r\n"
+"Image2\r\n"
+"--LEVEL2--\r\n"
+"\r\n"
+"--LEVEL1--\r\n"
+"";
+
+ vmime::shared_ptr <vmime::message> msg = vmime::make_shared <vmime::message>();
+ msg->parse(msgString);
+
+ // Sanity checks
+ VASSERT_EQ("part-count1", 2, msg->getBody()->getPartCount());
+ VASSERT_EQ("part-count2", 3, msg->getBody()->getPartAt(1)->getBody()->getPartCount());
+
+ vmime::htmlTextPart htmlPart;
+ htmlPart.parse(
+ msg, msg->getBody()->getPartAt(1),
+ msg->getBody()->getPartAt(1)->getBody()->getPartAt(1)
+ );
+
+ // Two embedded objects should be found.
+ // BUGFIX: "CID:" prefix is not case-sensitive.
+ VASSERT_EQ("count", 2, htmlPart.getObjectCount());
+
+ // Ensure the right objects have been found.
+ VASSERT_EQ("has-obj1", true, htmlPart.hasObject("image1@test"));
+ VASSERT_EQ("has-obj2", true, htmlPart.hasObject("image2@test"));
+
+ // hasObject() should also work with prefixes
+ VASSERT_EQ("has-obj1-pre", true, htmlPart.hasObject("CID:image1@test"));
+ VASSERT_EQ("has-obj2-pre", true, htmlPart.hasObject("cid:image2@test"));
+
+ // Check data in objects
+ vmime::shared_ptr <const vmime::htmlTextPart::embeddedObject> obj;
+
+ obj = htmlPart.findObject("image1@test");
+
+ VASSERT_EQ("ref-type1", vmime::htmlTextPart::embeddedObject::REFERENCED_BY_ID, obj->getReferenceType());
+ VASSERT_EQ("id-obj1", "image1@test", obj->getId());
+ VASSERT_EQ("data-obj1", "Image1", extractContent(obj->getData()));
+ VASSERT_EQ("type-obj1", "image/png", obj->getType().generate());
+
+ obj = htmlPart.findObject("image2@test");
+
+ VASSERT_EQ("ref-type2", vmime::htmlTextPart::embeddedObject::REFERENCED_BY_ID, obj->getReferenceType());
+ VASSERT_EQ("id-obj2", "image2@test", obj->getId());
+ VASSERT_EQ("data-obj2", "Image2", extractContent(obj->getData()));
+ VASSERT_EQ("type-obj2", "image/jpeg", obj->getType().generate());
+ }
+
+ /** Test parsing of embedded objects by location.
+ */
+ void testParseEmbeddedObjectsLocation() {
+
+ const vmime::string msgString = ""
+"MIME-Version: 1.0\r\n"
+"Content-Type: multipart/alternative; boundary=\"LEVEL1\"\r\n"
+"\r\n"
+"--LEVEL1\r\n"
+"Content-Type: text/plain; charset=\"x-ch1\"\r\n"
+"\r\n"
+"Plain text part\r\n"
+"--LEVEL1\r\n"
+"Content-Type: multipart/related; boundary=\"LEVEL2\"\r\n"
+"\r\n"
+"--LEVEL2\r\n"
+"Content-Type: image/png; name=\"image1.png\"\r\n"
+"Content-Location: http://www.vmime.org/test/image1.png\r\n"
+"Content-Disposition: inline; filename=\"image1.png\"\r\n"
+"Content-Id: <image1@test>\r\n"
+"\r\n"
+"Image1\r\n"
+"--LEVEL2\r\n"
+"Content-Type: text/html; charset=\"x-ch2\"\r\n"
+"\r\n"
+"<img src=\"http://www.vmime.org/test/image1.png\"/>\r\n"
+"--LEVEL2--\r\n"
+"\r\n"
+"--LEVEL1--\r\n"
+"";
+
+ vmime::shared_ptr <vmime::message> msg = vmime::make_shared <vmime::message>();
+ msg->parse(msgString);
+
+ // Sanity checks
+ VASSERT_EQ("part-count1", 2, msg->getBody()->getPartCount());
+ VASSERT_EQ("part-count2", 2, msg->getBody()->getPartAt(1)->getBody()->getPartCount());
+
+ vmime::htmlTextPart htmlPart;
+ htmlPart.parse(
+ msg, msg->getBody()->getPartAt(1),
+ msg->getBody()->getPartAt(1)->getBody()->getPartAt(1)
+ );
+
+ // Only one embedded object
+ VASSERT_EQ("count", 1, htmlPart.getObjectCount());
+
+ // Should work only with Content-Location as the Content-Id is
+ // not referenced in the HTML contents
+ VASSERT_EQ("has-obj-loc", true, htmlPart.hasObject("http://www.vmime.org/test/image1.png"));
+ VASSERT_EQ("has-obj-cid", false, htmlPart.hasObject("image1@test"));
+
+ // Check data
+ vmime::shared_ptr <const vmime::htmlTextPart::embeddedObject> obj;
+
+ obj = htmlPart.findObject("http://www.vmime.org/test/image1.png");
+
+ VASSERT_EQ("ref-type", vmime::htmlTextPart::embeddedObject::REFERENCED_BY_LOCATION, obj->getReferenceType());
+ VASSERT_EQ("id-obj", "http://www.vmime.org/test/image1.png", obj->getId());
+ VASSERT_EQ("data-obj", "Image1", extractContent(obj->getData()));
+ VASSERT_EQ("type-obj", "image/png", obj->getType().generate());
+ }
+
+ // TODO: test generation of text parts
+
+VMIME_TEST_SUITE_END
diff --git a/vmime-master/tests/parser/mailboxGroupTest.cpp b/vmime-master/tests/parser/mailboxGroupTest.cpp
new file mode 100644
index 0000000..18ff425
--- /dev/null
+++ b/vmime-master/tests/parser/mailboxGroupTest.cpp
@@ -0,0 +1,107 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "tests/testUtils.hpp"
+
+
+VMIME_TEST_SUITE_BEGIN(mailboxGroupTest)
+
+ VMIME_TEST_LIST_BEGIN
+ VMIME_TEST(testParseExtraWhitespaces)
+ VMIME_TEST(testParseNoEndDelimiter)
+ VMIME_TEST(testParseExtraChars)
+ VMIME_TEST(testEmptyGroup)
+ VMIME_TEST(testEncodedEmptyGroup)
+ VMIME_TEST_LIST_END
+
+
+ void testParseExtraWhitespaces() {
+
+ vmime::mailboxGroup mgrp;
+ mgrp.parse(" \t group : aaa <aaa@vmime.org>, bbb <bbb@vmime.org>");
+
+ VASSERT_EQ("name", "group", mgrp.getName().getWholeBuffer());
+ VASSERT_EQ("count", 2, mgrp.getMailboxCount());
+
+ VASSERT_EQ("mbox1.email", "aaa@vmime.org", mgrp.getMailboxAt(0)->getEmail());
+ VASSERT_EQ("mbox1.name", "aaa", mgrp.getMailboxAt(0)->getName());
+
+ VASSERT_EQ("mbox2.email", "bbb@vmime.org", mgrp.getMailboxAt(1)->getEmail());
+ VASSERT_EQ("mbox2.name", "bbb", mgrp.getMailboxAt(1)->getName());
+ }
+
+ void testParseNoEndDelimiter() {
+
+ vmime::addressList addrs;
+ addrs.parse("group: aaa <aaa@vmime.org>, bbb <bbb@vmime.org>");
+
+ VASSERT_EQ("count", 1, addrs.getAddressCount());
+ VASSERT_TRUE("is group", addrs.getAddressAt(0)->isGroup());
+
+ vmime::shared_ptr <vmime::mailboxGroup> mgrp =
+ vmime::dynamicCast <vmime::mailboxGroup>(addrs.getAddressAt(0));
+
+ VASSERT_EQ("name", "group", mgrp->getName().getWholeBuffer());
+ VASSERT_EQ("count", 2, mgrp->getMailboxCount());
+
+ VASSERT_EQ("mbox1.email", "aaa@vmime.org", mgrp->getMailboxAt(0)->getEmail());
+ VASSERT_EQ("mbox1.name", "aaa", mgrp->getMailboxAt(0)->getName());
+
+ VASSERT_EQ("mbox2.email", "bbb@vmime.org", mgrp->getMailboxAt(1)->getEmail());
+ VASSERT_EQ("mbox2.name", "bbb", mgrp->getMailboxAt(1)->getName());
+ }
+
+ void testParseExtraChars() {
+
+ vmime::mailboxGroup mgrp;
+ mgrp.parse("group: aaa <aaa@vmime.org>, bbb <bbb@vmime.org>; extra chars here...");
+
+ VASSERT_EQ("name", "group", mgrp.getName().getWholeBuffer());
+ VASSERT_EQ("count", 2, mgrp.getMailboxCount());
+
+ VASSERT_EQ("mbox1.email", "aaa@vmime.org", mgrp.getMailboxAt(0)->getEmail());
+ VASSERT_EQ("mbox1.name", "aaa", mgrp.getMailboxAt(0)->getName());
+
+ VASSERT_EQ("mbox2.email", "bbb@vmime.org", mgrp.getMailboxAt(1)->getEmail());
+ VASSERT_EQ("mbox2.name", "bbb", mgrp.getMailboxAt(1)->getName());
+ }
+
+ void testEmptyGroup() {
+
+ vmime::mailboxGroup mgrp;
+ mgrp.parse("Undisclosed recipients:;");
+
+ VASSERT_EQ("name", "Undisclosed recipients", mgrp.getName().getWholeBuffer());
+ VASSERT_EQ("count", 0, mgrp.getMailboxCount());
+ }
+
+ void testEncodedEmptyGroup() {
+
+ vmime::mailboxGroup mgrp;
+ mgrp.parse("=?us-ascii?Q?Undisclosed_recipients?=:;");
+
+ VASSERT_EQ("name", "Undisclosed recipients", mgrp.getName().getWholeBuffer());
+ VASSERT_EQ("count", 0, mgrp.getMailboxCount());
+ }
+
+VMIME_TEST_SUITE_END
diff --git a/vmime-master/tests/parser/mailboxListTest.cpp b/vmime-master/tests/parser/mailboxListTest.cpp
new file mode 100644
index 0000000..7505acd
--- /dev/null
+++ b/vmime-master/tests/parser/mailboxListTest.cpp
@@ -0,0 +1,47 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "tests/testUtils.hpp"
+
+
+VMIME_TEST_SUITE_BEGIN(mailboxListTest)
+
+ VMIME_TEST_LIST_BEGIN
+ VMIME_TEST(testParseGroup)
+ VMIME_TEST_LIST_END
+
+
+ // Disposition-Notification-To:: <email@domain.com>
+ void testParseGroup() {
+
+ // Groups should be extracted to multiple mailboxes in mailbox lists
+ vmime::mailboxList mboxList;
+ mboxList.parse("email1@domain1.com, : <email2@domain2.com>, email3@domain3.com");
+
+ VASSERT_EQ("count", 3, mboxList.getMailboxCount());
+ VASSERT_EQ("email", "email1@domain1.com", mboxList.getMailboxAt(0)->getEmail().generate());
+ VASSERT_EQ("email", "email2@domain2.com", mboxList.getMailboxAt(1)->getEmail().generate());
+ VASSERT_EQ("email", "email3@domain3.com", mboxList.getMailboxAt(2)->getEmail().generate());
+ }
+
+VMIME_TEST_SUITE_END
diff --git a/vmime-master/tests/parser/mailboxTest.cpp b/vmime-master/tests/parser/mailboxTest.cpp
new file mode 100644
index 0000000..997a6a3
--- /dev/null
+++ b/vmime-master/tests/parser/mailboxTest.cpp
@@ -0,0 +1,187 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "tests/testUtils.hpp"
+
+
+VMIME_TEST_SUITE_BEGIN(mailboxTest)
+
+ VMIME_TEST_LIST_BEGIN
+ VMIME_TEST(testParse)
+ VMIME_TEST(testEmptyEmailAddress)
+ VMIME_TEST(testSeparatorInComment)
+ VMIME_TEST(testMalformations)
+ VMIME_TEST(testExcessiveQuoting)
+ VMIME_TEST_LIST_END
+
+
+ void testParse() {
+
+ static const vmime::string testSuitesParse[] = {
+
+ // Test 1
+ "My (this is a comment)name <me(another \\)comment) @ somewhere(else).com>",
+
+ "[address-list: [[mailbox: name=[text: [[word: charset=us-ascii, buffer=My name]]], email=me@somewhere.com]]]",
+
+ // Test 2
+ "mailbox1 <mailbox@one>,;,,, ,, ,,;group1:mailbox1@group1, mailbox2@group2,,\"mailbox #3\" <mailbox3@group2>;, <mailbox@two>,,,,,,,,=?iso-8859-1?q?mailbox_number_3?= <mailbox@three>, =?abc?Q?mailbox?= =?def?Q?_number_4?= <mailbox@four>",
+
+ "[address-list: [[mailbox: name=[text: [[word: charset=us-ascii, buffer=mailbox1]]], email=mailbox@one],[mailbox-group: name=[text: [[word: charset=us-ascii, buffer=group1]]], list=[[mailbox: name=[text: []], email=mailbox1@group1],[mailbox: name=[text: []], email=mailbox2@group2],[mailbox: name=[text: [[word: charset=us-ascii, buffer=mailbox #3]]], email=mailbox3@group2]]],[mailbox: name=[text: []], email=mailbox@two],[mailbox: name=[text: [[word: charset=iso-8859-1, buffer=mailbox number 3]]], email=mailbox@three],[mailbox: name=[text: [[word: charset=abc, buffer=mailbox],[word: charset=def, buffer= number 4]]], email=mailbox@four]]]",
+
+ // Test 3
+ "John Doe <john.doe@acme.com>",
+
+ "[address-list: [[mailbox: name=[text: [[word: charset=us-ascii, buffer=John Doe]]], email=john.doe@acme.com]]]",
+
+ // Test 4
+ "john.doe@acme.com (John Doe)",
+
+ "[address-list: [[mailbox: name=[text: []], email=john.doe@acme.com]]]",
+
+ // Test 5
+ "John.Doe(ignore)@acme.com (John Doe)",
+
+ "[address-list: [[mailbox: name=[text: []], email=John.Doe@acme.com]]]",
+
+ // Test 6
+ "<john.doe@acme.com>",
+
+ "[address-list: [[mailbox: name=[text: []], email=john.doe@acme.com]]]",
+
+ // Test 7
+ "john.doe@acme.com",
+
+ "[address-list: [[mailbox: name=[text: []], email=john.doe@acme.com]]]",
+
+ // Test 8
+ "\"John Doe\" <john.doe@acme.com>",
+
+ "[address-list: [[mailbox: name=[text: [[word: charset=us-ascii, buffer=John Doe]]], email=john.doe@acme.com]]]",
+
+ // Test 9
+ "=?us-ascii?q?John?=<john.doe@acme.com>",
+
+ "[address-list: [[mailbox: name=[text: [[word: charset=us-ascii, buffer=John]]], email=john.doe@acme.com]]]",
+
+ // Test 10
+ "\"John\"<john.doe@acme.com>",
+
+ "[address-list: [[mailbox: name=[text: [[word: charset=us-ascii, buffer=John]]], email=john.doe@acme.com]]]",
+
+ // Test 11
+ "John<john.doe@acme.com>",
+
+ "[address-list: [[mailbox: name=[text: [[word: charset=us-ascii, buffer=John]]], email=john.doe@acme.com]]]"
+ };
+
+ for (unsigned int i = 0 ; i < sizeof(testSuitesParse) / sizeof(testSuitesParse[0]) / 2 ; ++i) {
+
+ vmime::string in = testSuitesParse[i * 2];
+ vmime::string out = testSuitesParse[i * 2 + 1];
+
+ std::ostringstream oss;
+ oss << "Test " << (i + 1);
+
+ vmime::addressList addrList;
+ addrList.parse(in);
+
+ std::ostringstream cmp;
+ cmp << addrList;
+
+ VASSERT_EQ(oss.str(), out, cmp.str());
+ }
+ }
+
+ void testEmptyEmailAddress() {
+
+ vmime::addressList addrList;
+ addrList.parse("\"Full Name\" <>");
+
+ VASSERT_EQ("count", 1, addrList.getAddressCount());
+ VASSERT_EQ("!group", false, addrList.getAddressAt(0)->isGroup());
+
+ vmime::shared_ptr <vmime::mailbox> mbox =
+ vmime::dynamicCast <vmime::mailbox>(addrList.getAddressAt(0));
+
+ VASSERT_EQ("name", "Full Name", mbox->getName());
+ VASSERT_EQ("email", "", mbox->getEmail());
+ }
+
+ void testSeparatorInComment() {
+
+ vmime::addressList addrList;
+ addrList.parse("aaa(comment,comment)@vmime.org, bbb@vmime.org");
+
+ VASSERT_EQ("count", 2, addrList.getAddressCount());
+
+ vmime::shared_ptr <vmime::mailbox> mbox1 =
+ vmime::dynamicCast <vmime::mailbox>(addrList.getAddressAt(0));
+ vmime::shared_ptr <vmime::mailbox> mbox2 =
+ vmime::dynamicCast <vmime::mailbox>(addrList.getAddressAt(1));
+
+ VASSERT_EQ("name1", vmime::text(), mbox1->getName());
+ VASSERT_EQ("email1", "aaa@vmime.org", mbox1->getEmail());
+
+ VASSERT_EQ("name2", vmime::text(), mbox2->getName());
+ VASSERT_EQ("email2", "bbb@vmime.org", mbox2->getEmail());
+ }
+
+ void testMalformations() {
+ vmime::mailbox mbox;
+
+ mbox.parse("a@b.c <e@f.g>");
+ VASSERT_EQ("name", vmime::text("a@b.c"), mbox.getName());
+ VASSERT_EQ("email", "e@f.g", mbox.getEmail());
+
+ mbox.parse("a@b.c e@f.g <h@i.j>");
+ VASSERT_EQ("name", vmime::text("a@b.c e@f.g"), mbox.getName());
+ VASSERT_EQ("email", "h@i.j", mbox.getEmail());
+
+ mbox.parse("Foo <bar<baz@quux.com>");
+ VASSERT_EQ("name", vmime::text("Foo <bar"), mbox.getName());
+ VASSERT_EQ("email", "baz@quux.com", mbox.getEmail());
+
+ mbox.parse("Foo <foo@x.com> <bar@x.com>");
+ VASSERT_EQ("name", vmime::text("Foo <foo@x.com>"), mbox.getName());
+ VASSERT_EQ("email", "bar@x.com", mbox.getEmail());
+
+ mbox.parse("Foo <foo@x.com> Bar <bar@y.com>");
+ VASSERT_EQ("name", vmime::text("Foo <foo@x.com> Bar"), mbox.getName());
+ VASSERT_EQ("email", "bar@y.com", mbox.getEmail());
+ }
+
+ void testExcessiveQuoting() {
+ using namespace vmime;
+
+ // Check that ASCII display names are not encoded more than necessary
+ emailAddress e("a@b.com");
+ auto a = make_shared<mailbox>(text(word("Foo B@r", charsets::US_ASCII)), e);
+ VASSERT_EQ("generate", "\"Foo B@r\" <a@b.com>", a->generate());
+ VASSERT_NEQ("generate", "=?utf-8?Q?Foo_B=40r?= <a@b.com>", a->generate());
+
+ a = make_shared<mailbox>(text(word("Foo B@r", charsets::UTF_8)), e);
+ VASSERT_EQ("generate", "=?utf-8?Q?Foo_B=40r?= <a@b.com>", a->generate());
+ }
+
+VMIME_TEST_SUITE_END
diff --git a/vmime-master/tests/parser/mediaTypeTest.cpp b/vmime-master/tests/parser/mediaTypeTest.cpp
new file mode 100644
index 0000000..e98cfcd
--- /dev/null
+++ b/vmime-master/tests/parser/mediaTypeTest.cpp
@@ -0,0 +1,100 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "tests/testUtils.hpp"
+
+
+VMIME_TEST_SUITE_BEGIN(mediaTypeTest)
+
+ VMIME_TEST_LIST_BEGIN
+ VMIME_TEST(testConstructors)
+ VMIME_TEST(testCopy)
+ VMIME_TEST(testSetFromString)
+ VMIME_TEST(testParse)
+ VMIME_TEST(testGenerate)
+ VMIME_TEST_LIST_END
+
+
+ void testConstructors() {
+
+ vmime::mediaType t1;
+
+ VASSERT_EQ("1.1", vmime::mediaTypes::APPLICATION, t1.getType());
+ VASSERT_EQ("1.2", vmime::mediaTypes::APPLICATION_OCTET_STREAM, t1.getSubType());
+
+ vmime::mediaType t2("type", "sub");
+
+ VASSERT_EQ("2.1", "type", t2.getType());
+ VASSERT_EQ("2.2", "sub", t2.getSubType());
+
+ vmime::mediaType t3("type/sub");
+
+ VASSERT_EQ("3.1", "type", t3.getType());
+ VASSERT_EQ("3.2", "sub", t3.getSubType());
+ }
+
+ void testCopy() {
+
+ vmime::mediaType t1("type/sub");
+
+ VASSERT_EQ("eq1", "type", t1.getType());
+ VASSERT_EQ("eq2", "sub", t1.getSubType());
+
+ VASSERT("operator==", t1 == t1);
+ VASSERT("clone", t1 == *vmime::clone(t1));
+
+ VASSERT_EQ("eq3", "type", vmime::clone(t1)->getType());
+ VASSERT_EQ("eq4", "sub", vmime::clone(t1)->getSubType());
+
+ vmime::mediaType t2;
+ t2.copyFrom(t1);
+
+ VASSERT("copyFrom", t1 == t2);
+ }
+
+ void testSetFromString() {
+
+ vmime::mediaType t1;
+ t1.setFromString("type/sub");
+
+ VASSERT_EQ("1.1", "type", t1.getType());
+ VASSERT_EQ("1.2", "sub", t1.getSubType());
+ }
+
+ void testParse() {
+
+ vmime::mediaType t1;
+ t1.parse("type/sub");
+
+ VASSERT_EQ("1.1", "type", t1.getType());
+ VASSERT_EQ("1.2", "sub", t1.getSubType());
+ }
+
+ void testGenerate() {
+
+ vmime::mediaType t1("type", "sub");
+
+ VASSERT_EQ("1", "type/sub", t1.generate());
+ }
+
+VMIME_TEST_SUITE_END
diff --git a/vmime-master/tests/parser/messageIdSequenceTest.cpp b/vmime-master/tests/parser/messageIdSequenceTest.cpp
new file mode 100644
index 0000000..0237108
--- /dev/null
+++ b/vmime-master/tests/parser/messageIdSequenceTest.cpp
@@ -0,0 +1,78 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "tests/testUtils.hpp"
+
+
+VMIME_TEST_SUITE_BEGIN(messageIdSequenceTest)
+
+ VMIME_TEST_LIST_BEGIN
+ VMIME_TEST(testParse)
+ VMIME_TEST(testGenerate)
+ VMIME_TEST_LIST_END
+
+
+ void testParse() {
+
+ vmime::messageIdSequence s1;
+ s1.parse("");
+
+ VASSERT_EQ("1", 0, s1.getMessageIdCount());
+
+ vmime::messageIdSequence s2;
+ s2.parse(" \t ");
+
+ VASSERT_EQ("2", 0, s2.getMessageIdCount());
+
+ vmime::messageIdSequence s3;
+ s3.parse("<a@b>");
+
+ VASSERT_EQ("3.1", 1, s3.getMessageIdCount());
+ VASSERT_EQ("3.2", "a", s3.getMessageIdAt(0)->getLeft());
+ VASSERT_EQ("3.3", "b", s3.getMessageIdAt(0)->getRight());
+
+ vmime::messageIdSequence s4;
+ s4.parse("<a@b> \r\n\t<c@d>");
+
+ VASSERT_EQ("4.1", 2, s4.getMessageIdCount());
+ VASSERT_EQ("4.2", "a", s4.getMessageIdAt(0)->getLeft());
+ VASSERT_EQ("4.3", "b", s4.getMessageIdAt(0)->getRight());
+ VASSERT_EQ("4.4", "c", s4.getMessageIdAt(1)->getLeft());
+ VASSERT_EQ("4.5", "d", s4.getMessageIdAt(1)->getRight());
+ }
+
+ void testGenerate() {
+
+ vmime::messageIdSequence s1;
+ s1.appendMessageId(vmime::make_shared <vmime::messageId>("a", "b"));
+
+ VASSERT_EQ("1", "<a@b>", s1.generate());
+
+ vmime::messageIdSequence s2;
+ s2.appendMessageId(vmime::make_shared <vmime::messageId>("a", "b"));
+ s2.appendMessageId(vmime::make_shared <vmime::messageId>("c", "d"));
+
+ VASSERT_EQ("2", "<a@b> <c@d>", s2.generate());
+ }
+
+VMIME_TEST_SUITE_END
diff --git a/vmime-master/tests/parser/messageIdTest.cpp b/vmime-master/tests/parser/messageIdTest.cpp
new file mode 100644
index 0000000..8433093
--- /dev/null
+++ b/vmime-master/tests/parser/messageIdTest.cpp
@@ -0,0 +1,77 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "tests/testUtils.hpp"
+
+
+VMIME_TEST_SUITE_BEGIN(messageIdTest)
+
+ VMIME_TEST_LIST_BEGIN
+ VMIME_TEST(testParse)
+ VMIME_TEST(testParseInvalid)
+ VMIME_TEST(testGenerate)
+ VMIME_TEST_LIST_END
+
+
+ void testParse() {
+
+ vmime::messageId m1;
+ m1.parse("<a@b>");
+
+ VASSERT_EQ("1.1", "a", m1.getLeft());
+ VASSERT_EQ("1.2", "b", m1.getRight());
+ }
+
+ void testParseInvalid() {
+
+ vmime::messageId m1;
+ m1.parse("foo@bar");
+
+ VASSERT_EQ("1.1", "foo", m1.getLeft());
+ VASSERT_EQ("1.2", "bar", m1.getRight());
+ }
+
+ void testGenerate() {
+
+ vmime::messageId m1;
+
+ VASSERT_EQ("1", "<>", m1.generate());
+
+ vmime::messageId m2;
+ m2.setLeft("a");
+
+ VASSERT_EQ("2", "<a>", m2.generate());
+
+ vmime::messageId m3;
+ m3.setRight("b");
+
+ VASSERT_EQ("3", "<@b>", m3.generate());
+
+ vmime::messageId m4;
+ m4.setLeft("a");
+ m4.setRight("b");
+
+ VASSERT_EQ("4", "<a@b>", m4.generate());
+ }
+
+VMIME_TEST_SUITE_END
diff --git a/vmime-master/tests/parser/messageTest.cpp b/vmime-master/tests/parser/messageTest.cpp
new file mode 100644
index 0000000..b89d63e
--- /dev/null
+++ b/vmime-master/tests/parser/messageTest.cpp
@@ -0,0 +1,64 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "tests/testUtils.hpp"
+
+
+VMIME_TEST_SUITE_BEGIN(messageTest)
+
+ VMIME_TEST_LIST_BEGIN
+ VMIME_TEST(testGetGeneratedSize)
+ VMIME_TEST_LIST_END
+
+
+ void testGetGeneratedSize() {
+
+ vmime::generationContext ctx;
+
+ vmime::shared_ptr <vmime::message> msg = vmime::make_shared <vmime::message>();
+ msg->getHeader()->getField("Foo")->setValue(vmime::string("bar"));
+
+ vmime::htmlTextPart textPart;
+ textPart.setPlainText(
+ vmime::make_shared <vmime::stringContentHandler>(
+ "Foo bar bazé foo foo foo"
+ )
+ );
+ textPart.setText(
+ vmime::make_shared <vmime::stringContentHandler>(
+ "Foo bar <strong>bazé</strong> foo foo foo"
+ )
+ );
+ textPart.generateIn(msg, msg);
+
+ // Estimated/computed generated size must be greater than the actual generated size
+ const vmime::size_t genSize = msg->getGeneratedSize(ctx);
+ const vmime::size_t actualSize = msg->generate().length();
+
+ std::ostringstream oss;
+ oss << "estimated size (" << genSize << ") >= actual size (" << actualSize << ")";
+
+ VASSERT(oss.str(), genSize >= actualSize);
+ }
+
+VMIME_TEST_SUITE_END
diff --git a/vmime-master/tests/parser/parameterTest.cpp b/vmime-master/tests/parser/parameterTest.cpp
new file mode 100644
index 0000000..464c305
--- /dev/null
+++ b/vmime-master/tests/parser/parameterTest.cpp
@@ -0,0 +1,722 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "tests/testUtils.hpp"
+
+#include <locale>
+#include <clocale>
+
+
+VMIME_TEST_SUITE_BEGIN(parameterTest)
+
+ VMIME_TEST_LIST_BEGIN
+ VMIME_TEST(testParse)
+ VMIME_TEST(testParseRFC2231)
+ VMIME_TEST(testGenerate)
+ VMIME_TEST(testGetGeneratedSize)
+ VMIME_TEST(testGenerateRFC2231)
+ VMIME_TEST(testGetGeneratedSizeRFC2231)
+ VMIME_TEST(testNonStandardEncodedParam)
+ VMIME_TEST(testParseNonSignificantWS)
+ VMIME_TEST(testEncodeTSpecials)
+ VMIME_TEST(testEncodeTSpecialsInRFC2231)
+ VMIME_TEST(testWhitespaceBreaksTheValue)
+ VMIME_TEST_LIST_END
+
+
+ // HACK: parameterizedHeaderField constructor is private
+ class parameterizedHeaderField : public vmime::parameterizedHeaderField {
+
+ public:
+
+ parameterizedHeaderField() {
+
+ setName("F");
+ setValue(vmime::headerFieldFactory::getInstance()->createValue(getName()));
+ setValue(vmime::word("X"));
+ }
+
+ using vmime::parameterizedHeaderField::generate;
+
+ const vmime::string generate(
+ const vmime::generationContext::EncodedParameterValueModes genMode,
+ const vmime::size_t maxLineLength = 0
+ ) const {
+
+ vmime::generationContext ctx(vmime::generationContext::getDefaultContext());
+ ctx.setEncodedParameterValueMode(genMode);
+
+ if (maxLineLength != 0) {
+ ctx.setMaxLineLength(maxLineLength);
+ }
+
+ std::ostringstream oss;
+ vmime::utility::outputStreamAdapter adapter(oss);
+
+ vmime::parameterizedHeaderField::generate(ctx, adapter);
+
+ return oss.str();
+ }
+ };
+
+
+ const vmime::string generateParameter(
+ const vmime::parameter& param,
+ const vmime::generationContext& ctx,
+ const vmime::size_t maxLineLength = 0
+ ) const {
+
+ vmime::generationContext ctx2(ctx);
+
+ if (maxLineLength != 0) {
+ ctx2.setMaxLineLength(maxLineLength);
+ }
+
+ std::ostringstream oss;
+ vmime::utility::outputStreamAdapter adapter(oss);
+
+ param.generate(ctx2, adapter);
+
+ return oss.str();
+ }
+
+
+#define FIELD_VALUE(f) (f.getValue()->generate())
+#define PARAM_VALUE(p, n) (p.getParameterAt(n)->getValue().generate())
+#define PARAM_NAME(p, n) (p.getParameterAt(n)->getName())
+#define PARAM_CHARSET(p, n) \
+ (p.getParameterAt(n)->getValue().getCharset().generate())
+#define PARAM_LANG(p, n) \
+ (p.getParameterAt(n)->getValue().getLanguage())
+#define PARAM_BUFFER(p, n) \
+ (p.getParameterAt(n)->getValue().getBuffer())
+
+
+ void setUp() {
+
+ // Set the global C and C++ locale to the user-configured locale.
+ // The locale should use UTF-8 encoding for these tests to run successfully.
+ try {
+ std::locale::global(std::locale(""));
+ } catch (std::exception &) {
+ std::setlocale(LC_ALL, "");
+ }
+ }
+
+ void tearDown() {
+
+ // Restore default locale
+ std::locale::global(std::locale("C"));
+ }
+
+
+ void testParse() {
+
+ // Simple parameter
+ parameterizedHeaderField p1;
+ p1.parse("X; param1=value1;\r\n");
+
+ VASSERT_EQ("1.1", 1, p1.getParameterCount());
+ VASSERT_EQ("1.2", "param1", PARAM_NAME(p1, 0));
+ VASSERT_EQ("1.3", "value1", PARAM_VALUE(p1, 0));
+
+ // Multi-section parameters (1/2)
+ parameterizedHeaderField p2a;
+ p2a.parse(
+ "X; param1=value1;\r\n"
+ " param2*0=\"val\";\r\n"
+ " param2*1=\"ue2\";"
+ );
+
+ VASSERT_EQ("2a.1", 2, p2a.getParameterCount());
+ VASSERT_EQ("2a.2", "param1", PARAM_NAME(p2a, 0));
+ VASSERT_EQ("2a.3", "value1", PARAM_VALUE(p2a, 0));
+ VASSERT_EQ("2a.4", "param2", PARAM_NAME(p2a, 1));
+ VASSERT_EQ("2a.5", "value2", PARAM_VALUE(p2a, 1));
+
+ // Multi-section parameters (2/2)
+ parameterizedHeaderField p2b;
+ p2b.parse(
+ "X; param1=value1;\r\n"
+ " param2=\"should be ignored\";\r\n"
+ " param2*0=\"val\";\r\n"
+ " param2*1=\"ue2\";"
+ );
+
+ VASSERT_EQ("2b.1", 2, p2b.getParameterCount());
+ VASSERT_EQ("2b.2", "param1", PARAM_NAME(p2b, 0));
+ VASSERT_EQ("2b.3", "value1", PARAM_VALUE(p2b, 0));
+ VASSERT_EQ("2b.4", "param2", PARAM_NAME(p2b, 1));
+ VASSERT_EQ("2b.5", "value2", PARAM_VALUE(p2b, 1));
+
+ // Extended parameter (charset and language information)
+ parameterizedHeaderField p3;
+ p3.parse("X; param1*=charset'language'value1;\r\n");
+
+ VASSERT_EQ("3.1", 1, p3.getParameterCount());
+ VASSERT_EQ("3.2", "param1", PARAM_NAME(p3, 0));
+ VASSERT_EQ("3.3", "charset", PARAM_CHARSET(p3, 0));
+ VASSERT_EQ("3.4", "value1", PARAM_BUFFER(p3, 0));
+
+ // Encoded characters in extended parameter values
+ parameterizedHeaderField p4;
+ p4.parse("X; param1*=a%20value%20with%20multiple%20word%73"); // 0x73 = 's'
+
+ VASSERT_EQ("4.1", 1, p4.getParameterCount());
+ VASSERT_EQ("4.2", "param1", PARAM_NAME(p4, 0));
+ VASSERT_EQ("4.3", "a value with multiple words", PARAM_VALUE(p4, 0));
+
+ // Invalid encoded character
+ parameterizedHeaderField p5;
+ p5.parse("X; param1*=test%20value%");
+
+ VASSERT_EQ("5.1", 1, p5.getParameterCount());
+ VASSERT_EQ("5.2", "param1", PARAM_NAME(p5, 0));
+ VASSERT_EQ("5.3", "test value%", PARAM_VALUE(p5, 0));
+
+ // Spaces before and after '='
+ parameterizedHeaderField p6;
+ p6.parse("X; param1\t= \"value1\"");
+
+ VASSERT_EQ("6.1", 1, p6.getParameterCount());
+ VASSERT_EQ("6.2", "param1", PARAM_NAME(p6, 0));
+ VASSERT_EQ("6.3", "value1", PARAM_VALUE(p6, 0));
+
+ // Quoted strings and escaped chars
+ parameterizedHeaderField p7;
+ p7.parse("X; param1=\"this is a slash: \\\"\\\\\\\"\""); // \"\\\"
+
+ VASSERT_EQ("7.1", 1, p7.getParameterCount());
+ VASSERT_EQ("7.2", "param1", PARAM_NAME(p7, 0));
+ VASSERT_EQ("7.3", "this is a slash: \"\\\"", PARAM_VALUE(p7, 0));
+ }
+
+ void testParseRFC2231() {
+
+ // Extended parameter with charset specified in more than one
+ // section (this is forbidden by RFC, but is should not fail)
+ parameterizedHeaderField p1;
+ p1.parse(
+ "X; param1*0*=charset1'language1'value1;\r\n"
+ " param1*1*=charset2'language2'value2;"
+ );
+
+ VASSERT_EQ("1.1", 1, p1.getParameterCount());
+ VASSERT_EQ("1.2", "param1", PARAM_NAME(p1, 0));
+ VASSERT_EQ("1.3", "charset1", PARAM_CHARSET(p1, 0));
+ VASSERT_EQ("1.4", "value1charset2'language2'value2", PARAM_BUFFER(p1, 0));
+
+ // Charset not specified in the first section (that is not encoded),
+ // but specified in the second one (legal)
+ parameterizedHeaderField p2;
+ p2.parse(
+ "X; param1*0=value1;\r\n"
+ " param1*1*=charset'language'value2;"
+ );
+
+ VASSERT_EQ("2.1", 1, p2.getParameterCount());
+ VASSERT_EQ("2.2", "param1", PARAM_NAME(p2, 0));
+ VASSERT_EQ("2.3", "charset", PARAM_CHARSET(p2, 0));
+ VASSERT_EQ("2.4", "value1value2", PARAM_BUFFER(p2, 0));
+
+ // Characters prefixed with '%' in a simple (not extended) section
+ // should not be decoded
+ parameterizedHeaderField p3;
+ p3.parse("X; param1=val%20ue1");
+
+ VASSERT_EQ("3.1", 1, p3.getParameterCount());
+ VASSERT_EQ("3.2", "param1", PARAM_NAME(p3, 0));
+ VASSERT_EQ("3.3", "val%20ue1", PARAM_VALUE(p3, 0));
+
+ // Multiple sections + charset specified and encoding
+ parameterizedHeaderField p4;
+ p4.parse(
+ "X; param1*0*=charset'language'value1a%20;"
+ " param1*1*=value1b%20;"
+ " param1*2=value1c"
+ );
+
+ VASSERT_EQ("4.1", 1, p4.getParameterCount());
+ VASSERT_EQ("4.2", "param1", PARAM_NAME(p4, 0));
+ VASSERT_EQ("4.3", "charset", PARAM_CHARSET(p4, 0));
+ VASSERT_EQ("4.4", "value1a value1b value1c", PARAM_BUFFER(p4, 0));
+
+ // No charset specified: defaults to US-ASCII
+ parameterizedHeaderField p5;
+ p5.parse("X; param1*='language'value1");
+
+ VASSERT_EQ("5.1", 1, p5.getParameterCount());
+ VASSERT_EQ("5.2", "param1", PARAM_NAME(p5, 0));
+ VASSERT_EQ("5.3", "us-ascii", PARAM_CHARSET(p5, 0));
+ VASSERT_EQ("5.4", "value1", PARAM_BUFFER(p5, 0));
+
+ // Language specification
+ parameterizedHeaderField p6;
+ p6.parse("X; param1*=us-ascii'en-us'This%20is%20%2A%2A%2Afun%2A%2A%2A");
+
+ VASSERT_EQ("6.1", 1, p6.getParameterCount());
+ VASSERT_EQ("6.2", "param1", PARAM_NAME(p6, 0));
+ VASSERT_EQ("6.3", "us-ascii", PARAM_CHARSET(p6, 0));
+ VASSERT_EQ("6.4", "en-us", PARAM_LANG(p6, 0));
+ VASSERT_EQ("6.5", "This is ***fun***", PARAM_BUFFER(p6, 0));
+ }
+
+ void testGenerate() {
+
+ // Simple parameter/value
+ parameterizedHeaderField p1;
+ p1.appendParameter(vmime::make_shared <vmime::parameter>("param1", "value1"));
+
+ VASSERT_EQ("1", "F: X; param1=value1", p1.generate());
+
+ // Value that needs quoting (1/2)
+ parameterizedHeaderField p2a;
+ p2a.appendParameter(vmime::make_shared <vmime::parameter>("param1", "value1a;value1b"));
+
+ VASSERT_EQ("2a", "F: X; param1=\"value1a;value1b\"", p2a.generate());
+
+ // Value that needs quoting (2/2)
+ parameterizedHeaderField p2b;
+ p2b.appendParameter(vmime::make_shared <vmime::parameter>("param1", "va\\lue\"1"));
+
+ VASSERT_EQ("2b", "F: X; param1=\"va\\\\lue\\\"1\"", p2b.generate());
+ }
+
+ void testGetGeneratedSize() {
+
+ vmime::generationContext ctx(vmime::generationContext::getDefaultContext());
+
+ vmime::parameter p1("param1", "value1");
+ VASSERT("1", p1.getGeneratedSize(ctx) >= generateParameter(p1, ctx).length());
+
+ vmime::parameter p2a("param1", "value1a;value1b");
+ VASSERT("2&", p2a.getGeneratedSize(ctx) >= generateParameter(p2a, ctx).length());
+
+ vmime::parameter p2b("param1", "va\\lue\"1");
+ VASSERT("1", p2b.getGeneratedSize(ctx) >= generateParameter(p2b, ctx).length());
+ }
+
+ void testGenerateRFC2231() {
+
+ // Extended parameter with charset specifier
+ parameterizedHeaderField p1;
+ p1.appendParameter(
+ vmime::make_shared <vmime::parameter>(
+ "param1",
+ vmime::word("value 1\xe9", vmime::charset("charset"))
+ )
+ );
+
+ VASSERT_EQ(
+ "1.no-encoding",
+ "F: X; param1=\"value 1\"",
+ p1.generate(vmime::generationContext::PARAMETER_VALUE_NO_ENCODING)
+ );
+
+ VASSERT_EQ(
+ "1.rfc2047",
+ "F: X; param1=\"=?charset?Q?value_1=E9?=\"",
+ p1.generate(vmime::generationContext::PARAMETER_VALUE_RFC2047_ONLY)
+ );
+
+ VASSERT_EQ(
+ "1.rfc2231",
+ "F: X; param1*=charset''value%201%E9",
+ p1.generate(vmime::generationContext::PARAMETER_VALUE_RFC2231_ONLY)
+ );
+
+ VASSERT_EQ(
+ "1.both",
+ "F: X; param1=\"=?charset?Q?value_1=E9?=\";param1*=charset''value%201%E9",
+ p1.generate(vmime::generationContext::PARAMETER_VALUE_RFC2231_AND_RFC2047)
+ );
+
+ // Value that spans on multiple lines
+ parameterizedHeaderField p2;
+ p2.appendParameter(
+ vmime::make_shared <vmime::parameter>(
+ "param1",
+ vmime::word(
+ "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ",
+ vmime::charset("charset")
+ )
+ )
+ );
+
+ VASSERT_EQ(
+ "2.no-encoding",
+ "F: X; \r\n "
+ "param1=abcdefghijkl",
+ p2.generate(vmime::generationContext::PARAMETER_VALUE_NO_ENCODING, 25) // max line length = 25
+ );
+
+ VASSERT_EQ(
+ "2.rfc2047",
+ "F: X; \r\n "
+ "param1=abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ",
+ p2.generate(vmime::generationContext::PARAMETER_VALUE_RFC2047_ONLY, 25) // max line length = 25
+ );
+
+ VASSERT_EQ(
+ "2.rfc2231",
+ "F: X; \r\n "
+ "param1*0*=charset''abc;\r\n "
+ "param1*1*=defghijkl;\r\n "
+ "param1*2*=mnopqrstu;\r\n "
+ "param1*3*=vwxyzABCD;\r\n "
+ "param1*4*=EFGHIJKLM;\r\n "
+ "param1*5*=NOPQRSTUV;\r\n "
+ "param1*6*=WXYZ",
+ p2.generate(vmime::generationContext::PARAMETER_VALUE_RFC2231_ONLY, 25) // max line length = 25
+ );
+
+ VASSERT_EQ(
+ "2.both",
+ "F: X; \r\n "
+ "param1=abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ;\r\n "
+ "param1*0*=charset''abc;\r\n "
+ "param1*1*=defghijkl;\r\n "
+ "param1*2*=mnopqrstu;\r\n "
+ "param1*3*=vwxyzABCD;\r\n "
+ "param1*4*=EFGHIJKLM;\r\n "
+ "param1*5*=NOPQRSTUV;\r\n "
+ "param1*6*=WXYZ",
+ p2.generate(vmime::generationContext::PARAMETER_VALUE_RFC2231_AND_RFC2047, 25) // max line length = 25
+ );
+
+ // Non-ASCII parameter value
+ parameterizedHeaderField p3;
+ p3.appendParameter(
+ vmime::make_shared <vmime::parameter>(
+ "param1",
+ vmime::word(
+ "δσσσσσσσσσσσσσσσσσσσσδσδα δσαδσδσαδσαδασδασ δσαδασδσα δσαδασδσα δασδασδασ δασαχφδδσα 2008.doc",
+ vmime::charset("utf-8")
+ )
+ )
+ );
+
+ VASSERT_EQ(
+ "3.no-encoding",
+ "F: X; \r\n "
+ "param1=\" 2008.doc\"",
+ p3.generate(vmime::generationContext::PARAMETER_VALUE_NO_ENCODING, 80) // max line length = 80
+ );
+
+ VASSERT_EQ(
+ "3.7bit-only",
+ "F: X; \r\n "
+ "param1=\"=?utf-8?B?zrTPg8+Dz4PPg8+Dz4PPg8+Dz4PPg8+Dz4PPg8+Dz4PPg8+Dz4PPg8+DzrTPg860?=\r\n "
+ "=?utf-8?B?zrEgzrTPg86xzrTPg860z4POsc60z4POsc60zrHPg860zrHPgyDOtM+DzrHOtM6x?=\r\n "
+ "=?utf-8?B?z4POtM+DzrEgzrTPg86xzrTOsc+DzrTPg86xIM60zrHPg860zrHPg860zrHPgyDOtA==?=\r\n "
+ "=?utf-8?B?zrHPg86xz4fPhs60zrTPg86xIDIwMDguZG9j?=\"",
+ p3.generate(vmime::generationContext::PARAMETER_VALUE_RFC2047_ONLY, 80) // max line length = 80
+ );
+
+ VASSERT_EQ(
+ "3.both",
+ "F: X; \r\n "
+ "param1=\"=?utf-8?B?zrTPg8+Dz4PPg8+Dz4PPg8+Dz4PPg8+Dz4PPg8+Dz4PPg8+Dz4PPg8+DzrTPg860?=\r\n "
+ "=?utf-8?B?zrEgzrTPg86xzrTPg860z4POsc60z4POsc60zrHPg860zrHPgyDOtM+DzrHOtM6x?=\r\n "
+ "=?utf-8?B?z4POtM+DzrEgzrTPg86xzrTOsc+DzrTPg86xIM60zrHPg860zrHPg860zrHPgyDOtA==?=\r\n "
+ "=?utf-8?B?zrHPg86xz4fPhs60zrTPg86xIDIwMDguZG9j?=\";\r\n "
+ "param1*0*=utf-8''%CE%B4%CF%83%CF%83%CF%83%CF%83%CF%83%CF%83%CF%83%CF%83%CF%83;\r\n "
+ "param1*1*=%CF%83%CF%83%CF%83%CF%83%CF%83%CF%83%CF%83%CF%83%CF%83%CF%83%CF%83;\r\n "
+ "param1*2*=%CE%B4%CF%83%CE%B4%CE%B1%20%CE%B4%CF%83%CE%B1%CE%B4%CF%83%CE%B4%CF;\r\n "
+ "param1*3*=%83%CE%B1%CE%B4%CF%83%CE%B1%CE%B4%CE%B1%CF%83%CE%B4%CE%B1%CF%83%20;\r\n "
+ "param1*4*=%CE%B4%CF%83%CE%B1%CE%B4%CE%B1%CF%83%CE%B4%CF%83%CE%B1%20%CE%B4%CF;\r\n "
+ "param1*5*=%83%CE%B1%CE%B4%CE%B1%CF%83%CE%B4%CF%83%CE%B1%20%CE%B4%CE%B1%CF%83;\r\n "
+ "param1*6*=%CE%B4%CE%B1%CF%83%CE%B4%CE%B1%CF%83%20%CE%B4%CE%B1%CF%83%CE%B1%CF;\r\n "
+ "param1*7*=%87%CF%86%CE%B4%CE%B4%CF%83%CE%B1%202008.doc",
+ p3.generate(vmime::generationContext::PARAMETER_VALUE_RFC2231_AND_RFC2047, 80) // max line length = 80
+ );
+
+ VASSERT_EQ(
+ "3.either",
+ "F: X; param1*0*=utf-8''%CE%B4%CF%83%CF%83%CF%83%CF%83%CF%83%CF%83%CF%83%CF%83%CF%83;\r\n "
+ "param1*1*=%CF%83%CF%83%CF%83%CF%83%CF%83%CF%83%CF%83%CF%83%CF%83%CF%83%CF%83;\r\n "
+ "param1*2*=%CE%B4%CF%83%CE%B4%CE%B1%20%CE%B4%CF%83%CE%B1%CE%B4%CF%83%CE%B4%CF;\r\n "
+ "param1*3*=%83%CE%B1%CE%B4%CF%83%CE%B1%CE%B4%CE%B1%CF%83%CE%B4%CE%B1%CF%83%20;\r\n "
+ "param1*4*=%CE%B4%CF%83%CE%B1%CE%B4%CE%B1%CF%83%CE%B4%CF%83%CE%B1%20%CE%B4%CF;\r\n "
+ "param1*5*=%83%CE%B1%CE%B4%CE%B1%CF%83%CE%B4%CF%83%CE%B1%20%CE%B4%CE%B1%CF%83;\r\n "
+ "param1*6*=%CE%B4%CE%B1%CF%83%CE%B4%CE%B1%CF%83%20%CE%B4%CE%B1%CF%83%CE%B1%CF;\r\n "
+ "param1*7*=%87%CF%86%CE%B4%CE%B4%CF%83%CE%B1%202008.doc",
+ p3.generate(vmime::generationContext::PARAMETER_VALUE_RFC2231_ONLY, 80) // max line length = 80
+ );
+
+ // No encoding needed
+ parameterizedHeaderField p4;
+ p4.appendParameter(
+ vmime::make_shared <vmime::parameter>(
+ "param1",
+ vmime::word("va lue", vmime::charset("charset"))
+ )
+ );
+
+ VASSERT_EQ(
+ "4.no-encoding",
+ "F: X; param1=\"va lue\"",
+ p4.generate(vmime::generationContext::PARAMETER_VALUE_NO_ENCODING)
+ );
+
+ VASSERT_EQ(
+ "4.rfc2047",
+ "F: X; param1=\"va lue\"",
+ p4.generate(vmime::generationContext::PARAMETER_VALUE_RFC2047_ONLY)
+ );
+
+ VASSERT_EQ(
+ "4.rfc2231",
+ "F: X; param1=\"va lue\"",
+ p4.generate(vmime::generationContext::PARAMETER_VALUE_RFC2231_ONLY)
+ );
+
+ VASSERT_EQ(
+ "4.both",
+ "F: X; param1=\"va lue\"",
+ p4.generate(vmime::generationContext::PARAMETER_VALUE_RFC2231_AND_RFC2047)
+ );
+
+ // Language specification
+ parameterizedHeaderField p5;
+ p5.appendParameter(
+ vmime::make_shared <vmime::parameter>("param1",
+ vmime::word("This is ***fun***", vmime::charset("us-ascii"), "en-us"))
+ );
+
+ VASSERT_EQ(
+ "5.no-encoding",
+ "F: X; param1=\"This is ***fun***\"",
+ p5.generate(vmime::generationContext::PARAMETER_VALUE_NO_ENCODING)
+ );
+
+ VASSERT_EQ(
+ "5.rfc2047",
+ "F: X; param1=\"=?us-ascii*en-us?Q?This_is_***fun***?=\"",
+ p5.generate(vmime::generationContext::PARAMETER_VALUE_RFC2047_ONLY)
+ );
+
+ VASSERT_EQ(
+ "5.rfc2231",
+ "F: X; param1*=us-ascii''This%20is%20***fun***",
+ p5.generate(vmime::generationContext::PARAMETER_VALUE_RFC2231_ONLY)
+ );
+
+ VASSERT_EQ(
+ "5.both",
+ "F: X; "
+ "param1=\"=?us-ascii*en-us?Q?This_is_***fun***?=\";\r\n "
+ "param1*=us-ascii''This%20is%20***fun***",
+ p5.generate(vmime::generationContext::PARAMETER_VALUE_RFC2231_AND_RFC2047));
+ }
+
+ void testGetGeneratedSizeRFC2231() {
+
+ vmime::generationContext ctx(vmime::generationContext::getDefaultContext());
+
+ // Extended parameter with charset specifier
+ vmime::parameter p1(
+ "param1",
+ vmime::word("value 1\xe9", vmime::charset("charset"))
+ );
+
+ ctx.setEncodedParameterValueMode(vmime::generationContext::PARAMETER_VALUE_NO_ENCODING);
+ VASSERT("1.no-encoding", p1.getGeneratedSize(ctx) >= generateParameter(p1, ctx).length());
+
+ ctx.setEncodedParameterValueMode(vmime::generationContext::PARAMETER_VALUE_RFC2047_ONLY);
+ VASSERT("1.rfc2047", p1.getGeneratedSize(ctx) >= generateParameter(p1, ctx).length());
+
+ ctx.setEncodedParameterValueMode(vmime::generationContext::PARAMETER_VALUE_RFC2231_ONLY);
+ VASSERT("1.rfc2231", p1.getGeneratedSize(ctx) >= generateParameter(p1, ctx).length());
+
+ ctx.setEncodedParameterValueMode(vmime::generationContext::PARAMETER_VALUE_RFC2231_AND_RFC2047);
+ VASSERT("1.both", p1.getGeneratedSize(ctx) >= generateParameter(p1, ctx).length());
+
+ // Value that spans on multiple lines
+ vmime::parameter p2(
+ "param1",
+ vmime::word(
+ "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ",
+ vmime::charset("charset")
+ )
+ );
+
+ ctx.setMaxLineLength(25);
+ ctx.setEncodedParameterValueMode(vmime::generationContext::PARAMETER_VALUE_NO_ENCODING);
+ VASSERT("2.no-encoding", p2.getGeneratedSize(ctx) >= generateParameter(p2, ctx).length());
+
+ ctx.setEncodedParameterValueMode(vmime::generationContext::PARAMETER_VALUE_RFC2047_ONLY);
+ VASSERT("2.rfc2047", p2.getGeneratedSize(ctx) >= generateParameter(p2, ctx).length());
+
+ ctx.setEncodedParameterValueMode(vmime::generationContext::PARAMETER_VALUE_RFC2231_ONLY);
+ VASSERT("2.rfc2231", p2.getGeneratedSize(ctx) >= generateParameter(p2, ctx).length());
+
+ ctx.setEncodedParameterValueMode(vmime::generationContext::PARAMETER_VALUE_RFC2231_AND_RFC2047);
+ VASSERT("2.both", p2.getGeneratedSize(ctx) >= generateParameter(p2, ctx).length());
+
+ // Non-ASCII parameter value
+ vmime::parameter p3(
+ "param1",
+ vmime::word(
+ "δσσσσσσσσσσσσσσσσσσσσδσδα δσαδσδσαδσαδασδασ δσαδασδσα δσαδασδσα δασδασδασ δασαχφδδσα 2008.doc",
+ vmime::charset("utf-8")
+ )
+ );
+
+ ctx.setMaxLineLength(vmime::generationContext::getDefaultContext().getMaxLineLength());
+ ctx.setEncodedParameterValueMode(vmime::generationContext::PARAMETER_VALUE_NO_ENCODING);
+ VASSERT("3.no-encoding", p3.getGeneratedSize(ctx) >= generateParameter(p3, ctx).length());
+
+ ctx.setEncodedParameterValueMode(vmime::generationContext::PARAMETER_VALUE_RFC2047_ONLY);
+ VASSERT("3.rfc2047", p3.getGeneratedSize(ctx) >= generateParameter(p3, ctx).length());
+
+ ctx.setEncodedParameterValueMode(vmime::generationContext::PARAMETER_VALUE_RFC2231_ONLY);
+ VASSERT("3.rfc2231", p3.getGeneratedSize(ctx) >= generateParameter(p3, ctx).length());
+
+ ctx.setEncodedParameterValueMode(vmime::generationContext::PARAMETER_VALUE_RFC2231_AND_RFC2047);
+ VASSERT("3.both", p3.getGeneratedSize(ctx) >= generateParameter(p3, ctx).length());
+
+ // No encoding needed
+ vmime::parameter p4(
+ "param1",
+ vmime::word("va lue", vmime::charset("charset"))
+ );
+
+ ctx.setMaxLineLength(vmime::generationContext::getDefaultContext().getMaxLineLength());
+ ctx.setEncodedParameterValueMode(vmime::generationContext::PARAMETER_VALUE_NO_ENCODING);
+ VASSERT("4.no-encoding", p4.getGeneratedSize(ctx) >= generateParameter(p4, ctx).length());
+
+ ctx.setEncodedParameterValueMode(vmime::generationContext::PARAMETER_VALUE_RFC2047_ONLY);
+ VASSERT("4.rfc2047", p4.getGeneratedSize(ctx) >= generateParameter(p4, ctx).length());
+
+ ctx.setEncodedParameterValueMode(vmime::generationContext::PARAMETER_VALUE_RFC2231_ONLY);
+ VASSERT("4.rfc2231", p4.getGeneratedSize(ctx) >= generateParameter(p4, ctx).length());
+
+ ctx.setEncodedParameterValueMode(vmime::generationContext::PARAMETER_VALUE_RFC2231_AND_RFC2047);
+ VASSERT("4.both", p4.getGeneratedSize(ctx) >= generateParameter(p4, ctx).length());
+
+ // Language specification
+ vmime::parameter p5(
+ "param1",
+ vmime::word("This is ***fun***", vmime::charset("us-ascii"), "en-us")
+ );
+
+ ctx.setMaxLineLength(vmime::generationContext::getDefaultContext().getMaxLineLength());
+ ctx.setEncodedParameterValueMode(vmime::generationContext::PARAMETER_VALUE_NO_ENCODING);
+ VASSERT("5.no-encoding", p5.getGeneratedSize(ctx) >= generateParameter(p5, ctx).length());
+
+ ctx.setEncodedParameterValueMode(vmime::generationContext::PARAMETER_VALUE_RFC2047_ONLY);
+ VASSERT("5.rfc2047", p5.getGeneratedSize(ctx) >= generateParameter(p5, ctx).length());
+
+ ctx.setEncodedParameterValueMode(vmime::generationContext::PARAMETER_VALUE_RFC2231_ONLY);
+ VASSERT("5.rfc2231", p5.getGeneratedSize(ctx) >= generateParameter(p5, ctx).length());
+
+ ctx.setEncodedParameterValueMode(vmime::generationContext::PARAMETER_VALUE_RFC2231_AND_RFC2047);
+ VASSERT("5.both", p5.getGeneratedSize(ctx) >= generateParameter(p5, ctx).length());
+ }
+
+ void testNonStandardEncodedParam() {
+
+ // This syntax is non-standard (expressly prohibited
+ // by RFC-2047), but is used by Mozilla:
+ //
+ // Content-Type: image/png;
+ // name="=?us-ascii?Q?Logo_VMime=2Epng?="
+
+ parameterizedHeaderField p1;
+ p1.parse("image/png; name=\"=?us-ascii?Q?Logo_VMime=2Epng?=\"");
+
+ VASSERT_EQ("1.1", 1, p1.getParameterCount());
+ VASSERT_EQ("1.2", "name", PARAM_NAME(p1, 0));
+ VASSERT_EQ("1.3", "Logo VMime.png", PARAM_VALUE(p1, 0));
+
+ parameterizedHeaderField p2;
+ p2.parse("image/png; name=\"Logo =?us-ascii?Q?VMime=2Epng?=\"");
+
+ VASSERT_EQ("2.1", 1, p2.getParameterCount());
+ VASSERT_EQ("2.2", "name", PARAM_NAME(p2, 0));
+ VASSERT_EQ("2.3", "Logo VMime.png", PARAM_VALUE(p2, 0));
+ }
+
+ // Parse parameters with non-significant whitespaces
+ void testParseNonSignificantWS() {
+
+ parameterizedHeaderField p1;
+ p1.parse(" \t X \r\n");
+
+ VASSERT_EQ("1.1", "X", FIELD_VALUE(p1));
+
+ parameterizedHeaderField p2;
+ p2.parse(" X ; param1 = value1 \r\n");
+
+ VASSERT_EQ("2.1", 1, p2.getParameterCount());
+ VASSERT_EQ("2.2", "X", FIELD_VALUE(p2));
+ VASSERT_EQ("2.3", "param1", PARAM_NAME(p2, 0));
+ VASSERT_EQ("2.4", "value1", PARAM_VALUE(p2, 0));
+ }
+
+ // Encode "tspecials"
+ void testEncodeTSpecials() {
+
+ VASSERT_EQ(" 1", "p=\"val(ue\"", vmime::make_shared <vmime::parameter>("p", "val(ue")->generate());
+ VASSERT_EQ(" 2", "p=\"val)ue\"", vmime::make_shared <vmime::parameter>("p", "val)ue")->generate());
+ VASSERT_EQ(" 3", "p=\"val<ue\"", vmime::make_shared <vmime::parameter>("p", "val<ue")->generate());
+ VASSERT_EQ(" 4", "p=\"val>ue\"", vmime::make_shared <vmime::parameter>("p", "val>ue")->generate());
+ VASSERT_EQ(" 5", "p=\"val@ue\"", vmime::make_shared <vmime::parameter>("p", "val@ue")->generate());
+ VASSERT_EQ(" 6", "p=\"val,ue\"", vmime::make_shared <vmime::parameter>("p", "val,ue")->generate());
+ VASSERT_EQ(" 7", "p=\"val;ue\"", vmime::make_shared <vmime::parameter>("p", "val;ue")->generate());
+ VASSERT_EQ(" 8", "p=\"val:ue\"", vmime::make_shared <vmime::parameter>("p", "val:ue")->generate());
+ VASSERT_EQ(" 9", "p=\"val/ue\"", vmime::make_shared <vmime::parameter>("p", "val/ue")->generate());
+ VASSERT_EQ("10", "p=\"val[ue\"", vmime::make_shared <vmime::parameter>("p", "val[ue")->generate());
+ VASSERT_EQ("11", "p=\"val]ue\"", vmime::make_shared <vmime::parameter>("p", "val]ue")->generate());
+ VASSERT_EQ("12", "p=\"val?ue\"", vmime::make_shared <vmime::parameter>("p", "val?ue")->generate());
+ VASSERT_EQ("13", "p=\"val=ue\"", vmime::make_shared <vmime::parameter>("p", "val=ue")->generate());
+ VASSERT_EQ("14", "p=\"val ue\"", vmime::make_shared <vmime::parameter>("p", "val ue")->generate());
+ VASSERT_EQ("15", "p=\"val\tue\"", vmime::make_shared <vmime::parameter>("p", "val\tue")->generate());
+ }
+
+ // http://sourceforge.net/projects/vmime/forums/forum/237356/topic/3812278
+ void testEncodeTSpecialsInRFC2231() {
+
+ VASSERT_EQ(
+ "1",
+ "filename*=UTF-8''my_file_name_%C3%B6%C3%A4%C3%BC_%281%29.txt",
+ vmime::make_shared <vmime::parameter>(
+ "filename",
+ vmime::word("my_file_name_\xc3\xb6\xc3\xa4\xc3\xbc_(1).txt", "UTF-8")
+ )->generate()
+ );
+ }
+
+ void testWhitespaceBreaksTheValue() {
+
+ parameterizedHeaderField p;
+ p.parse("xxx yyy; param1=value1 \r\n");
+
+ VASSERT_EQ("count", 1, p.getParameterCount());
+ VASSERT_EQ("value", "xxx", FIELD_VALUE(p));
+ VASSERT_EQ("param1.name", "param1", PARAM_NAME(p, 0));
+ VASSERT_EQ("param1.value", "value1", PARAM_VALUE(p, 0));
+ }
+
+VMIME_TEST_SUITE_END
diff --git a/vmime-master/tests/parser/pathTest.cpp b/vmime-master/tests/parser/pathTest.cpp
new file mode 100644
index 0000000..1396911
--- /dev/null
+++ b/vmime-master/tests/parser/pathTest.cpp
@@ -0,0 +1,102 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "tests/testUtils.hpp"
+
+
+VMIME_TEST_SUITE_BEGIN(pathTest)
+
+ VMIME_TEST_LIST_BEGIN
+ VMIME_TEST(testParse)
+ VMIME_TEST(testParse2)
+ VMIME_TEST(testGenerate)
+ VMIME_TEST_LIST_END
+
+
+ void testParse() {
+
+ vmime::path p1;
+ p1.parse("<>");
+
+ VASSERT_EQ("1.1", "", p1.getLocalPart());
+ VASSERT_EQ("1.2", "", p1.getDomain());
+
+ vmime::path p2;
+ p2.parse("<domain>");
+
+ VASSERT_EQ("2.1", "", p2.getLocalPart());
+ VASSERT_EQ("2.2", "domain", p2.getDomain());
+
+ vmime::path p3;
+ p3.parse("<local@domain>");
+
+ VASSERT_EQ("3.1", "local", p3.getLocalPart());
+ VASSERT_EQ("3.2", "domain", p3.getDomain());
+ }
+
+ void testParse2() {
+
+ // Test some invalid paths (no '<>')
+ vmime::path p1;
+ p1.parse("");
+
+ VASSERT_EQ("1.1", "", p1.getLocalPart());
+ VASSERT_EQ("1.2", "", p1.getDomain());
+
+ vmime::path p2;
+ p2.parse("domain");
+
+ VASSERT_EQ("2.1", "", p2.getLocalPart());
+ VASSERT_EQ("2.2", "domain", p2.getDomain());
+
+ vmime::path p3;
+ p3.parse("local@domain");
+
+ VASSERT_EQ("3.1", "local", p3.getLocalPart());
+ VASSERT_EQ("3.2", "domain", p3.getDomain());
+ }
+
+ void testGenerate() {
+
+ vmime::path p1;
+
+ VASSERT_EQ("1", "<>", p1.generate());
+
+ vmime::path p2;
+ p2.setLocalPart("local");
+
+ VASSERT_EQ("2", "<local@>", p2.generate());
+
+ vmime::path p3;
+ p3.setDomain("domain");
+
+ VASSERT_EQ("3", "<@domain>", p3.generate());
+
+ vmime::path p4;
+ p4.setLocalPart("local");
+ p4.setDomain("domain");
+
+ VASSERT_EQ("4", "<local@domain>", p4.generate());
+ }
+
+VMIME_TEST_SUITE_END
diff --git a/vmime-master/tests/parser/streamContentHandlerTest.cpp b/vmime-master/tests/parser/streamContentHandlerTest.cpp
new file mode 100644
index 0000000..399118e
--- /dev/null
+++ b/vmime-master/tests/parser/streamContentHandlerTest.cpp
@@ -0,0 +1,194 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "tests/testUtils.hpp"
+
+#include "vmime/utility/outputStreamAdapter.hpp"
+
+
+VMIME_TEST_SUITE_BEGIN(streamContentHandlerTest)
+
+ VMIME_TEST_LIST_BEGIN
+ VMIME_TEST(testIsEmpty)
+ VMIME_TEST(testGetLength)
+ VMIME_TEST(testIsEncoded)
+ VMIME_TEST(testGetLength_Encoded)
+ VMIME_TEST(testExtract)
+ VMIME_TEST(testExtract_Encoded)
+ VMIME_TEST(testExtractRaw_Encoded)
+ VMIME_TEST(testGenerate)
+ VMIME_TEST(testGenerate_Encoded)
+ VMIME_TEST_LIST_END
+
+
+ void testIsEmpty() {
+
+ vmime::streamContentHandler cth;
+
+ VASSERT_TRUE("empty", cth.isEmpty());
+ }
+
+ void testGetLength() {
+
+ vmime::string data("Test Data");
+ vmime::shared_ptr <vmime::utility::inputStream> stream =
+ vmime::make_shared <vmime::utility::inputStreamStringAdapter>(data);
+
+ vmime::streamContentHandler cth(stream, data.length());
+
+ VASSERT_FALSE("empty", cth.isEmpty());
+ VASSERT_EQ("length", 9, cth.getLength());
+ }
+
+ void testIsEncoded() {
+
+ vmime::string data("Test Data");
+ vmime::shared_ptr <vmime::utility::inputStream> stream =
+ vmime::make_shared <vmime::utility::inputStreamStringAdapter>(data);
+
+ vmime::streamContentHandler cth(stream, data.length());
+
+ VASSERT_FALSE("encoded", cth.isEncoded());
+ VASSERT_EQ("encoding", vmime::contentHandler::NO_ENCODING, cth.getEncoding());
+
+
+ vmime::string data2("Zm9vEjRWYmFy=");
+ vmime::shared_ptr <vmime::utility::inputStream> stream2 =
+ vmime::make_shared <vmime::utility::inputStreamStringAdapter>(data2);
+
+ vmime::streamContentHandler cth2(stream2, data2.length(), vmime::encoding("base64"));
+
+ VASSERT_TRUE("encoded", cth2.isEncoded());
+ VASSERT_EQ("encoding", "base64", cth2.getEncoding().generate());
+ }
+
+ void testGetLength_Encoded() {
+
+ vmime::string data("foo=12=34=56bar");
+ vmime::shared_ptr <vmime::utility::inputStream> stream =
+ vmime::make_shared <vmime::utility::inputStreamStringAdapter>(data);
+
+ vmime::streamContentHandler cth(stream, data.length(), vmime::encoding("quoted-printable"));
+
+ // Reported length should be the length of encoded data
+ VASSERT_EQ("length", 15, cth.getLength());
+ }
+
+ void testExtract() {
+
+ vmime::string data("Test Data");
+ vmime::shared_ptr <vmime::utility::inputStream> stream =
+ vmime::make_shared <vmime::utility::inputStreamStringAdapter>(data);
+
+ vmime::streamContentHandler cth(stream, data.length());
+
+ std::ostringstream oss;
+ vmime::utility::outputStreamAdapter osa(oss);
+
+ cth.extract(osa);
+
+ VASSERT_EQ("extract", "Test Data", oss.str());
+ }
+
+ void testExtract_Encoded() {
+
+ vmime::string data(
+ "QUJDREVGR0hJSktMTU5PUFFSU1RVVldYWVphYmNkZWZnaGlqa2xtbm9wcXJzdHV2d3h5ejAxMjM0NTY3ODk="
+ );
+
+ vmime::shared_ptr <vmime::utility::inputStream> stream =
+ vmime::make_shared <vmime::utility::inputStreamStringAdapter>(data);
+
+ vmime::streamContentHandler cth(stream, data.length(), vmime::encoding("base64"));
+
+ std::ostringstream oss;
+ vmime::utility::outputStreamAdapter osa(oss);
+
+ cth.extract(osa);
+
+ // Data should be decoded from B64
+ VASSERT_EQ(
+ "extract",
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789",
+ oss.str()
+ );
+ }
+
+ void testExtractRaw_Encoded()
+ {
+ vmime::string data(
+ "QUJDREVGR0hJSktMTU5PUFFSU1RVVldYWVphYmNkZWZnaGlqa2xtbm9wcXJzdHV2d3h5ejAxMjM0NTY3ODk="
+ );
+ vmime::shared_ptr <vmime::utility::inputStream> stream =
+ vmime::make_shared <vmime::utility::inputStreamStringAdapter>(data);
+
+ vmime::streamContentHandler cth(stream, data.length(), vmime::encoding("base64"));
+
+ std::ostringstream oss;
+ vmime::utility::outputStreamAdapter osa(oss);
+
+ cth.extractRaw(osa);
+
+ // Data should not be decoded
+ VASSERT_EQ(
+ "extractRaw",
+ "QUJDREVGR0hJSktMTU5PUFFSU1RVVldYWVphYmNkZWZnaGlqa2xtbm9wcXJzdHV2d3h5ejAxMjM0NTY3ODk=",
+ oss.str()
+ );
+ }
+
+ void testGenerate() {
+
+ vmime::string data("foo\x12\x34\x56 bar");
+ vmime::shared_ptr <vmime::utility::inputStream> stream =
+ vmime::make_shared <vmime::utility::inputStreamStringAdapter>(data);
+
+ vmime::streamContentHandler cth(stream, data.length());
+
+ std::ostringstream oss;
+ vmime::utility::outputStreamAdapter osa(oss);
+
+ cth.generate(osa, vmime::encoding("base64"));
+
+ // Data should be encoded to B64
+ VASSERT_EQ("generate", "Zm9vEjRWIGJhcg==", oss.str());
+ }
+
+ void testGenerate_Encoded() {
+
+ vmime::string data("foo=12=34=56bar");
+ vmime::shared_ptr <vmime::utility::inputStream> stream =
+ vmime::make_shared <vmime::utility::inputStreamStringAdapter>(data);
+
+ vmime::streamContentHandler cth(stream, data.length(), vmime::encoding("quoted-printable"));
+
+ std::ostringstream oss;
+ vmime::utility::outputStreamAdapter osa(oss);
+
+ cth.generate(osa, vmime::encoding("base64"));
+
+ // Data should be reencoded from QP to B64
+ VASSERT_EQ("generate", "Zm9vEjRWYmFy", oss.str());
+ }
+
+VMIME_TEST_SUITE_END
diff --git a/vmime-master/tests/parser/stringContentHandlerTest.cpp b/vmime-master/tests/parser/stringContentHandlerTest.cpp
new file mode 100644
index 0000000..c856301
--- /dev/null
+++ b/vmime-master/tests/parser/stringContentHandlerTest.cpp
@@ -0,0 +1,165 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "tests/testUtils.hpp"
+
+#include "vmime/utility/outputStreamAdapter.hpp"
+
+
+VMIME_TEST_SUITE_BEGIN(stringContentHandlerTest)
+
+ VMIME_TEST_LIST_BEGIN
+ VMIME_TEST(testIsEmpty)
+ VMIME_TEST(testGetLength)
+ VMIME_TEST(testIsEncoded)
+ VMIME_TEST(testGetLength_Encoded)
+ VMIME_TEST(testExtract)
+ VMIME_TEST(testExtract_Encoded)
+ VMIME_TEST(testExtractRaw_Encoded)
+ VMIME_TEST(testGenerate)
+ VMIME_TEST(testGenerate_Encoded)
+ VMIME_TEST_LIST_END
+
+
+ void testIsEmpty() {
+
+ vmime::stringContentHandler cth;
+
+ VASSERT_TRUE("empty", cth.isEmpty());
+ }
+
+ void testGetLength() {
+
+ vmime::stringContentHandler cth("Test Data");
+
+ VASSERT_FALSE("empty", cth.isEmpty());
+ VASSERT_EQ("length", 9, cth.getLength());
+ }
+
+ void testIsEncoded() {
+
+ vmime::stringContentHandler cth("Test Data");
+
+ VASSERT_FALSE("encoded", cth.isEncoded());
+ VASSERT_EQ("encoding", vmime::contentHandler::NO_ENCODING, cth.getEncoding());
+
+
+ vmime::stringContentHandler cth2("Zm9vEjRWYmFy=", vmime::encoding("base64"));
+
+ VASSERT_TRUE("encoded", cth2.isEncoded());
+ VASSERT_EQ("encoding", "base64", cth2.getEncoding().generate());
+ }
+
+ void testGetLength_Encoded() {
+
+ vmime::stringContentHandler cth(
+ "foo=12=34=56bar",
+ vmime::encoding("quoted-printable")
+ );
+
+ // Reported length should be the length of encoded data
+ VASSERT_EQ("length", 15, cth.getLength());
+ }
+
+ void testExtract() {
+
+ vmime::stringContentHandler cth("Test Data");
+
+ std::ostringstream oss;
+ vmime::utility::outputStreamAdapter osa(oss);
+
+ cth.extract(osa);
+
+ VASSERT_EQ("extract", "Test Data", oss.str());
+ }
+
+ void testExtract_Encoded() {
+
+ vmime::stringContentHandler cth(
+ "QUJDREVGR0hJSktMTU5PUFFSU1RVVldYWVphYmNkZWZnaGlqa2xtbm9wcXJzdHV2d3h5ejAxMjM0NTY3ODk=",
+ vmime::encoding("base64")
+ );
+
+ std::ostringstream oss;
+ vmime::utility::outputStreamAdapter osa(oss);
+
+ cth.extract(osa);
+
+ // Data should be decoded from B64
+ VASSERT_EQ(
+ "extract",
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789",
+ oss.str()
+ );
+ }
+
+ void testExtractRaw_Encoded() {
+
+ vmime::stringContentHandler cth(
+ "QUJDREVGR0hJSktMTU5PUFFSU1RVVldYWVphYmNkZWZnaGlqa2xtbm9wcXJzdHV2d3h5ejAxMjM0NTY3ODk=",
+ vmime::encoding("base64")
+ );
+
+ std::ostringstream oss;
+ vmime::utility::outputStreamAdapter osa(oss);
+
+ cth.extractRaw(osa);
+
+ // Data should not be decoded
+ VASSERT_EQ(
+ "extractRaw",
+ "QUJDREVGR0hJSktMTU5PUFFSU1RVVldYWVphYmNkZWZnaGlqa2xtbm9wcXJzdHV2d3h5ejAxMjM0NTY3ODk=",
+ oss.str()
+ );
+ }
+
+ void testGenerate() {
+
+ vmime::stringContentHandler cth("foo\x12\x34\x56 bar");
+
+ std::ostringstream oss;
+ vmime::utility::outputStreamAdapter osa(oss);
+
+ cth.generate(osa, vmime::encoding("base64"));
+
+ // Data should be encoded to B64
+ VASSERT_EQ("generate", "Zm9vEjRWIGJhcg==", oss.str());
+ }
+
+ void testGenerate_Encoded() {
+
+ vmime::stringContentHandler cth(
+ "foo=12=34=56bar",
+ vmime::encoding("quoted-printable")
+ );
+
+ std::ostringstream oss;
+ vmime::utility::outputStreamAdapter osa(oss);
+
+ cth.generate(osa, vmime::encoding("base64"));
+
+ // Data should be reencoded from QP to B64
+ VASSERT_EQ("generate", "Zm9vEjRWYmFy", oss.str());
+ }
+
+VMIME_TEST_SUITE_END
diff --git a/vmime-master/tests/parser/textTest.cpp b/vmime-master/tests/parser/textTest.cpp
new file mode 100644
index 0000000..e9ddc26
--- /dev/null
+++ b/vmime-master/tests/parser/textTest.cpp
@@ -0,0 +1,918 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "tests/testUtils.hpp"
+
+#include <locale>
+#include <clocale>
+
+
+VMIME_TEST_SUITE_BEGIN(textTest)
+
+ VMIME_TEST_LIST_BEGIN
+ VMIME_TEST(testConstructors)
+ VMIME_TEST(testCopy)
+ VMIME_TEST(testNewFromString)
+ VMIME_TEST(testDisplayForm)
+ VMIME_TEST(testParse)
+ VMIME_TEST(testGenerate)
+
+ VMIME_TEST(testWordConstructors)
+ VMIME_TEST(testWordParse)
+ VMIME_TEST(testWordGenerate)
+ VMIME_TEST(testWordGenerateSpace)
+ VMIME_TEST(testWordGenerateSpace2)
+ VMIME_TEST(testWordGenerateMultiBytes)
+ VMIME_TEST(testWordGenerateQuote)
+ VMIME_TEST(testWordGenerateSpecialCharsets)
+ VMIME_TEST(testWordGenerateSpecials)
+
+ VMIME_TEST(testWhitespace)
+ VMIME_TEST(testWhitespaceMBox)
+
+ VMIME_TEST(testFoldingAscii)
+ VMIME_TEST(testForcedNonEncoding)
+
+ VMIME_TEST(testBugFix20110511)
+
+ VMIME_TEST(testInternationalizedEmail_specialChars)
+ VMIME_TEST(testInternationalizedEmail_UTF8)
+ VMIME_TEST(testInternationalizedEmail_nonUTF8)
+ VMIME_TEST(testInternationalizedEmail_folding)
+ VMIME_TEST(testInternationalizedEmail_whitespace)
+
+ VMIME_TEST(testWronglyPaddedB64Words)
+ VMIME_TEST(testFixBrokenWords)
+ VMIME_TEST(testUnknownCharset)
+ VMIME_TEST_LIST_END
+
+
+ static const vmime::string getDisplayText(const vmime::text& t) {
+
+ return t.getWholeBuffer();
+ }
+
+ static const vmime::string cleanGeneratedWords(const std::string& str) {
+
+ std::istringstream iss(str);
+
+ std::string res;
+ std::string x;
+
+ while (std::getline(iss, x)) {
+ res += vmime::utility::stringUtils::trim(x);
+ }
+
+ return res;
+ }
+
+
+ void setUp() {
+
+ // Set the global C and C++ locale to the user-configured locale.
+ // The locale should use UTF-8 encoding for these tests to run successfully.
+ try {
+ std::locale::global(std::locale(""));
+ } catch (std::exception &) {
+ std::setlocale(LC_ALL, "");
+ }
+ }
+
+ void tearDown() {
+
+ // Restore default locale
+ std::locale::global(std::locale("C"));
+ }
+
+
+ void testConstructors() {
+
+ vmime::text t1;
+
+ VASSERT_EQ("1.1", 0, t1.getWordCount());
+
+ vmime::text t2("Test\xa9\xc3");
+
+ VASSERT_EQ("2.1", 1, t2.getWordCount());
+ VASSERT_EQ("2.2", "Test\xa9\xc3", t2.getWordAt(0)->getBuffer());
+ VASSERT_EQ("2.3", vmime::charset::getLocalCharset(), t2.getWordAt(0)->getCharset());
+
+ vmime::text t3("Test\xa9\xc3", vmime::charset(vmime::charsets::ISO8859_13));
+
+ VASSERT_EQ("3.1", 1, t3.getWordCount());
+ VASSERT_EQ("3.2", "Test\xa9\xc3", t3.getWordAt(0)->getBuffer());
+ VASSERT_EQ("3.3", vmime::charset(vmime::charsets::ISO8859_13), t3.getWordAt(0)->getCharset());
+
+ vmime::word w1("Test", vmime::charset(vmime::charsets::UTF_8));
+ vmime::text t4(w1);
+
+ VASSERT_EQ("4.1", 1, t4.getWordCount());
+ VASSERT_EQ("4.2", w1.getBuffer(), t4.getWordAt(0)->getBuffer());
+ VASSERT_EQ("4.3", w1.getCharset(), t4.getWordAt(0)->getCharset());
+
+ vmime::word w2("Other", vmime::charset(vmime::charsets::US_ASCII));
+ t4.appendWord(vmime::make_shared <vmime::word>(w2));
+
+ vmime::text t5(t4);
+
+ VASSERT_EQ("5.1", 2, t5.getWordCount());
+ VASSERT_EQ("5.2", w1.getBuffer(), t5.getWordAt(0)->getBuffer());
+ VASSERT_EQ("5.3", w1.getCharset(), t5.getWordAt(0)->getCharset());
+ VASSERT_EQ("5.4", w2.getBuffer(), t5.getWordAt(1)->getBuffer());
+ VASSERT_EQ("5.5", w2.getCharset(), t5.getWordAt(1)->getCharset());
+ }
+
+ void testCopy() {
+
+ vmime::text t1("Test: \xa9\xc3");
+
+ VASSERT("operator==", t1 == t1);
+ VASSERT("clone", *vmime::clone(t1) == t1);
+
+ vmime::text t2;
+ t2.copyFrom(t1);
+
+ VASSERT("copyFrom", t1 == t2);
+ }
+
+ void testNewFromString() {
+
+ vmime::string s1 = "only ASCII characters";
+ vmime::charset c1("test");
+ vmime::text t1;
+
+ t1.createFromString(s1, c1);
+
+ VASSERT_EQ("1.1", 1, t1.getWordCount());
+ VASSERT_EQ("1.2", s1, t1.getWordAt(0)->getBuffer());
+ VASSERT_EQ("1.3", vmime::charset(vmime::charsets::US_ASCII), t1.getWordAt(0)->getCharset());
+
+ vmime::string s2_1 = "some ASCII characters and special chars: ";
+ vmime::string s2_2 = "\xf1\xf2\xf3\xf4 ";
+ vmime::string s2_3 = "and then more ASCII chars.";
+ vmime::string s2 = s2_1 + s2_2 + s2_3;
+ vmime::charset c2("test");
+ vmime::text t2;
+
+ t2.createFromString(s2, c2);
+
+ VASSERT_EQ("2.1", 3, t2.getWordCount());
+ VASSERT_EQ("2.2", "some ASCII characters and special chars: ", t2.getWordAt(0)->getBuffer());
+ VASSERT_EQ("2.3", vmime::charset(vmime::charsets::US_ASCII), t2.getWordAt(0)->getCharset());
+ VASSERT_EQ("2.4", "\xf1\xf2\xf3\xf4", t2.getWordAt(1)->getBuffer());
+ VASSERT_EQ("2.5", c2, t2.getWordAt(1)->getCharset());
+ VASSERT_EQ("2.6", "and then more ASCII chars.", t2.getWordAt(2)->getBuffer());
+ VASSERT_EQ("2.7", vmime::charset(vmime::charsets::US_ASCII), t2.getWordAt(2)->getCharset());
+ }
+
+ static const vmime::string parseText(const vmime::string& buffer) {
+
+ vmime::text t;
+ t.parse(buffer);
+
+ std::ostringstream oss;
+ oss << t;
+
+ return oss.str();
+ }
+
+ void testParse() {
+
+ // From RFC-2047
+ VASSERT_EQ(
+ "1",
+ "[text: [[word: charset=US-ASCII, buffer=Keith Moore]]]",
+ parseText("=?US-ASCII?Q?Keith_Moore?=")
+ );
+
+ VASSERT_EQ(
+ "2",
+ "[text: [[word: charset=ISO-8859-1, buffer=Keld J\xf8rn Simonsen]]]",
+ parseText("=?ISO-8859-1?Q?Keld_J=F8rn_Simonsen?=")
+ );
+
+ VASSERT_EQ(
+ "3",
+ "[text: [[word: charset=ISO-8859-1, buffer=Andr\xe9]," \
+ "[word: charset=us-ascii, buffer= Pirard]]]",
+ parseText("=?ISO-8859-1?Q?Andr=E9?= Pirard")
+ );
+
+ VASSERT_EQ(
+ "4",
+ "[text: [[word: charset=ISO-8859-1, buffer=If you can read this yo]," \
+ "[word: charset=ISO-8859-2, buffer=u understand the example.]]]",
+ parseText(
+ "=?ISO-8859-1?B?SWYgeW91IGNhbiByZWFkIHRoaXMgeW8=?=\r\n " \
+ "=?ISO-8859-2?B?dSB1bmRlcnN0YW5kIHRoZSBleGFtcGxlLg==?="
+ )
+ );
+
+ // Bugfix: in "=?charset?q?=XX=YY?=", the "?=" finish
+ // sequence was not correctly found (should be the one
+ // after '=YY' and not the one after '?q').
+ VASSERT_EQ(
+ "5",
+ "[text: [[word: charset=abc, buffer=\xe9\xe9]]]",
+ parseText("=?abc?q?=E9=E9?=")
+ );
+
+ // Question marks (?) in the middle of the string
+ VASSERT_EQ(
+ "6",
+ "[text: [[word: charset=iso-8859-1, buffer=Know wh\xe4t? It works!]]]",
+ parseText("=?iso-8859-1?Q?Know_wh=E4t?_It_works!?=")
+ );
+
+ // With language specifier
+ VASSERT_EQ(
+ "7",
+ "[text: [[word: charset=US-ASCII, buffer=Keith Moore, lang=EN]]]",
+ parseText("=?US-ASCII*EN?Q?Keith_Moore?=")
+ );
+ }
+
+ void testGenerate() {
+
+ // TODO
+
+ // With language specifier
+ vmime::word wlang1("Émeline", vmime::charset("UTF-8"), "FR");
+ VASSERT_EQ("lang1", "=?UTF-8*FR?Q?=C3=89meline?=", wlang1.generate());
+
+ vmime::word wlang2("Keith Moore", vmime::charset("US-ASCII"), "EN");
+ VASSERT_EQ("lang2", "=?US-ASCII*EN?Q?Keith_Moore?=", wlang2.generate());
+ }
+
+ void testDisplayForm() {
+
+#define DISPLAY_FORM(x) getDisplayText(*vmime::text::decodeAndUnfold(x))
+
+ // From RFC-2047
+ VASSERT_EQ("1", "a", DISPLAY_FORM("=?ISO-8859-1?Q?a?="));
+ VASSERT_EQ("2", "a b", DISPLAY_FORM("=?ISO-8859-1?Q?a?= b"));
+ VASSERT_EQ("3", "ab", DISPLAY_FORM("=?ISO-8859-1?Q?a?= =?ISO-8859-1?Q?b?="));
+ VASSERT_EQ("4", "ab", DISPLAY_FORM("=?ISO-8859-1?Q?a?= \t =?ISO-8859-1?Q?b?="));
+ VASSERT_EQ("5", "ab", DISPLAY_FORM("=?ISO-8859-1?Q?a?= \r\n \t =?ISO-8859-1?Q?b?="));
+ VASSERT_EQ("6", "a b", DISPLAY_FORM("=?ISO-8859-1?Q?a_b?="));
+ VASSERT_EQ("7", "a b", DISPLAY_FORM("=?ISO-8859-1?Q?a?= =?ISO-8859-2?Q?_b?="));
+
+ // Some more tests...
+ VASSERT_EQ("8", "a b", DISPLAY_FORM(" a =?ISO-8859-1?Q?b?= "));
+ VASSERT_EQ("9", "a b ", DISPLAY_FORM(" \t =?ISO-8859-1?Q?a?= b "));
+ VASSERT_EQ("10", "a b", DISPLAY_FORM(" a\r\n\t b"));
+
+ VASSERT_EQ("11", "a b c", DISPLAY_FORM("a =?ISO-8859-1?Q?b?= c"));
+ VASSERT_EQ("12", "a b c ", DISPLAY_FORM("a =?ISO-8859-1?Q?b?= c "));
+ VASSERT_EQ("13", "a b c ", DISPLAY_FORM(" a =?ISO-8859-1?Q?b?= c "));
+ VASSERT_EQ("14", "a b c d", DISPLAY_FORM("a =?ISO-8859-1?Q?b?= c =?ISO-8859-1?Q?d?= "));
+ VASSERT_EQ("15", "a b c d e", DISPLAY_FORM("a =?ISO-8859-1?Q?b?= c =?ISO-8859-1?Q?d?= e"));
+
+ // Whitespaces and multiline
+ VASSERT_EQ("16", "a b c d e", DISPLAY_FORM("=?ISO-8859-1?Q?a_b_?=c\n\t=?ISO-8859-1?Q?d_?=e"));
+
+ // Ignored newlines
+ VASSERT_EQ("17", "ab", DISPLAY_FORM("=?ISO-8859-1?Q?a?=\r\nb"));
+ VASSERT_EQ("18", "a b", DISPLAY_FORM("=?ISO-8859-1?Q?a?= \r\nb"));
+
+#undef DISPLAY_FORM
+ }
+
+ void testWordConstructors() {
+
+ VASSERT_EQ("1.1", vmime::charset::getLocalCharset(), vmime::word().getCharset());
+ VASSERT_EQ("1.2", "", vmime::word().getBuffer());
+
+ VASSERT_EQ("2.1", vmime::charset::getLocalCharset(), vmime::word("foo").getCharset());
+ VASSERT_EQ("2.2", "foo", vmime::word("foo").getBuffer());
+
+ VASSERT_EQ("3.1", "bar", vmime::word("foo", vmime::charset("bar")).getCharset().getName());
+ VASSERT_EQ("3.2", "foo", vmime::word("foo", vmime::charset("bar")).getBuffer());
+ }
+
+ void testWordParse() {
+
+ // Simple encoded word
+ vmime::word w1;
+ w1.parse("=?foo?q?bar=E9 baz?=");
+
+ VASSERT_EQ("1.1", "foo", w1.getCharset().getName());
+ VASSERT_EQ("1.2", "bar\xe9 baz", w1.getBuffer());
+
+ // Unencoded text
+ vmime::word w2;
+ w2.parse(" foo bar \tbaz...");
+
+ VASSERT_EQ("2.1", vmime::charset(vmime::charsets::US_ASCII), w2.getCharset());
+ VASSERT_EQ("2.2", " foo bar \tbaz...", w2.getBuffer());
+
+ // Malformed word
+ vmime::word w3;
+ w3.parse("=?foo bar");
+
+ VASSERT_EQ("3.1", vmime::charset(vmime::charsets::US_ASCII), w3.getCharset());
+ VASSERT_EQ("3.2", "=?foo bar", w3.getBuffer());
+
+ // Unknown encoding
+ vmime::word w4;
+ w4.parse("=?whatever?not_q_or_b?whatever?=");
+
+ VASSERT_EQ("4.1", vmime::charset(vmime::charsets::US_ASCII), w4.getCharset());
+ VASSERT_EQ("4.2", "=?whatever?not_q_or_b?whatever?=", w4.getBuffer());
+ }
+
+ void testWordGenerate() {
+
+ VASSERT_EQ(
+ "1",
+ "=?foo?Q?bar=E9_baz?=",
+ vmime::word("bar\xe9 baz", vmime::charset("foo")).generate()
+ );
+
+ VASSERT_EQ(
+ "2",
+ "=?foo?B?8fLz9PU=?=",
+ vmime::word("\xf1\xf2\xf3\xf4\xf5", vmime::charset("foo")).generate()
+ );
+ }
+
+ void testWordGenerateSpace() {
+
+ // No white-space between an unencoded word and a encoded one
+ VASSERT_EQ(
+ "1",
+ "Bonjour =?utf-8?Q?Fran=C3=A7ois?=",
+ vmime::text::newFromString(
+ "Bonjour Fran\xc3\xa7ois",
+ vmime::charset("utf-8")
+ )->generate()
+ );
+
+ // White-space between two encoded words
+ vmime::text txt;
+ txt.appendWord(vmime::make_shared <vmime::word>("\xc3\x89t\xc3\xa9", "utf-8"));
+ txt.appendWord(vmime::make_shared <vmime::word>("Fran\xc3\xa7ois", "utf-8"));
+
+ const vmime::string decoded = "\xc3\x89t\xc3\xa9""Fran\xc3\xa7ois";
+ const vmime::string encoded = "=?utf-8?B?w4l0w6k=?= =?utf-8?Q?Fran=C3=A7ois?=";
+
+ // -- test encoding
+ VASSERT_EQ("2", encoded, txt.generate());
+
+ // -- ensure no space is added when decoding
+ vmime::text txt2;
+ txt2.parse(encoded, 0, encoded.length());
+
+ VASSERT_EQ("3", decoded, txt2.getWholeBuffer());
+
+ // -- test rencoding
+ VASSERT_EQ("4", encoded, txt2.generate());
+ }
+
+ void testWordGenerateSpace2() {
+
+ // White-space between two encoded words (#2)
+ vmime::text txt;
+ txt.appendWord(vmime::make_shared <vmime::word>("Facture ", "utf-8"));
+ txt.appendWord(vmime::make_shared <vmime::word>("\xc3\xa0", "utf-8"));
+ txt.appendWord(vmime::make_shared <vmime::word>(" envoyer ", "utf-8"));
+ txt.appendWord(vmime::make_shared <vmime::word>("\xc3\xa0", "utf-8"));
+ txt.appendWord(vmime::make_shared <vmime::word>(" Martine", "utf-8"));
+
+ const vmime::string decoded = "Facture ""\xc3\xa0"" envoyer ""\xc3\xa0"" Martine";
+ const vmime::string encoded = "Facture =?utf-8?B?w6A=?= envoyer =?utf-8?B?w6A=?= Martine";
+
+ // -- test encoding
+ VASSERT_EQ("1", encoded, txt.generate());
+
+ // -- ensure no space is added when decoding
+ vmime::text txt2;
+ txt2.parse(encoded, 0, encoded.length());
+
+ VASSERT_EQ("2", decoded, txt2.getWholeBuffer());
+
+ // -- test rencoding
+ VASSERT_EQ("3", encoded, txt2.generate());
+ }
+
+ void testWordGenerateMultiBytes() {
+
+ // Ensure we don't encode a non-integral number of characters
+ VASSERT_EQ(
+ "1",
+ "=?utf-8?Q?aaa?==?utf-8?Q?=C3=A9?==?utf-8?Q?zzz?=",
+ cleanGeneratedWords(
+ vmime::word("aaa\xc3\xa9zzz", vmime::charset("utf-8")).generate(16)
+ )
+ );
+
+ VASSERT_EQ(
+ "2",
+ "=?utf-8?Q?aaa=C3=A9?==?utf-8?Q?zzz?=",
+ cleanGeneratedWords(
+ vmime::word("aaa\xc3\xa9zzz", vmime::charset("utf-8")).generate(17)
+ )
+ );
+ }
+
+ void testWordGenerateQuote() {
+
+ std::string str;
+ vmime::utility::outputStreamStringAdapter os(str);
+
+ vmime::generationContext ctx;
+ ctx.setMaxLineLength(1000);
+
+ // ASCII-only text is quotable
+ str.clear();
+ vmime::word("Quoted text")
+ .generate(ctx, os, 0, NULL, vmime::text::QUOTE_IF_POSSIBLE, NULL);
+
+ VASSERT_EQ("1", "\"Quoted text\"", cleanGeneratedWords(str));
+
+ // Text with CR/LF is not quotable
+ str.clear();
+ vmime::word("Non-quotable\ntext", "us-ascii")
+ .generate(ctx, os, 0, NULL, vmime::text::QUOTE_IF_POSSIBLE, NULL);
+
+ VASSERT_EQ("2", "=?us-ascii?Q?Non-quotable=0Atext?=", cleanGeneratedWords(str));
+
+ // Text with non-ASCII chars is not quotable
+ str.clear();
+ vmime::word("Non-quotable text \xc3\xa9")
+ .generate(ctx, os, 0, NULL, vmime::text::QUOTE_IF_POSSIBLE, NULL);
+
+ VASSERT_EQ("3", "=?UTF-8?Q?Non-quotable_text_=C3=A9?=", cleanGeneratedWords(str));
+ }
+
+ void testWordGenerateSpecialCharsets() {
+
+ // ISO-2022-JP only uses 7-bit chars but should be encoded in Base64
+ VASSERT_EQ(
+ "1",
+ "=?iso-2022-jp?B?XlskQiVRITwlPSVKJWshJiU9JVUlSCUmJSclIl5bKEI=?=",
+ cleanGeneratedWords(
+ vmime::word(
+ "^[$B%Q!<%=%J%k!&%=%U%H%&%'%\"^[(B",
+ vmime::charset("iso-2022-jp")
+ ).generate(100)
+ )
+ );
+ }
+
+ void testWordGenerateSpecials() {
+
+ // In RFC-2047, quotation marks (ASCII 22h) should be encoded
+ VASSERT_EQ(
+ "1",
+ "=?UTF-8?Q?=22=C3=9Cml=C3=A4ute=22?=",
+ vmime::word(
+ "\x22\xC3\x9Cml\xC3\xA4ute\x22",
+ vmime::charset("UTF-8")
+ ).generate()
+ );
+ }
+
+ void testWhitespace() {
+
+ // Create
+ vmime::text text;
+ text.createFromString("Achim Br\xc3\xa4ndt", vmime::charsets::UTF_8);
+
+ VASSERT_EQ("1", 2, text.getWordCount());
+ VASSERT_EQ("2", "Achim ", text.getWordAt(0)->getBuffer());
+ VASSERT_EQ("3", "us-ascii", text.getWordAt(0)->getCharset());
+ VASSERT_EQ("4", "Br\xc3\xa4ndt", text.getWordAt(1)->getBuffer());
+ VASSERT_EQ("5", "utf-8", text.getWordAt(1)->getCharset());
+
+ // Generate
+ VASSERT_EQ("6", "Achim =?utf-8?Q?Br=C3=A4ndt?=", text.generate());
+
+ // Parse
+ text.parse("=?us-ascii?Q?Achim_?= =?utf-8?Q?Br=C3=A4ndt?=");
+
+ VASSERT_EQ("7", 2, text.getWordCount());
+ VASSERT_EQ("8", "Achim ", text.getWordAt(0)->getBuffer());
+ VASSERT_EQ("9", "us-ascii", text.getWordAt(0)->getCharset());
+ VASSERT_EQ("10", "Br\xc3\xa4ndt", text.getWordAt(1)->getBuffer());
+ VASSERT_EQ("11", "utf-8", text.getWordAt(1)->getCharset());
+ }
+
+ void testWhitespaceMBox() {
+
+ // Space MUST be encoded inside a word
+ vmime::mailbox mbox(vmime::text("Achim Br\xc3\xa4ndt", vmime::charsets::UTF_8), "me@vmime.org");
+ VASSERT_EQ("generate1", "=?us-ascii?Q?Achim_?= =?utf-8?Q?Br=C3=A4ndt?= <me@vmime.org>", mbox.generate());
+
+ vmime::text txt;
+ txt.appendWord(vmime::make_shared <vmime::word>("Achim ", "us-ascii"));
+ txt.appendWord(vmime::make_shared <vmime::word>("Br\xc3\xa4ndt", "utf-8"));
+ mbox = vmime::mailbox(txt, "me@vmime.org");
+ VASSERT_EQ("generate2", "=?us-ascii?Q?Achim_?= =?utf-8?Q?Br=C3=A4ndt?= <me@vmime.org>", mbox.generate());
+
+ mbox.parse("=?us-ascii?Q?Achim?= =?utf-8?Q?Br=C3=A4ndt?= <me@vmime.org>");
+ VASSERT_EQ("parse.name.count", 2, mbox.getName().getWordCount());
+ VASSERT_EQ("parse.name.word1.buffer", "Achim", mbox.getName().getWordAt(0)->getBuffer());
+ VASSERT_EQ("parse.name.word1.charset", "us-ascii", mbox.getName().getWordAt(0)->getCharset());
+ VASSERT_EQ("parse.name.word2.buffer", "Br\xc3\xa4ndt", mbox.getName().getWordAt(1)->getBuffer());
+ VASSERT_EQ("parse.name.word2.charset", "utf-8", mbox.getName().getWordAt(1)->getCharset());
+
+ VASSERT_EQ("parse.email", "me@vmime.org", mbox.getEmail());
+ }
+
+ void testFoldingAscii() {
+
+ // In this test, no encoding is needed, but line should be folded anyway
+ vmime::word w("01234567890123456789012345678901234567890123456789"
+ "01234567890123456789012345678901234567890123456789", vmime::charset("us-ascii"));
+
+ VASSERT_EQ(
+ "fold.ascii",
+ "=?us-ascii?Q?01234567890123456789012345678901234?=\r\n"
+ " =?us-ascii?Q?5678901234567890123456789012345678?=\r\n"
+ " =?us-ascii?Q?9012345678901234567890123456789?=", w.generate(50)
+ );
+ }
+
+ void testForcedNonEncoding() {
+
+ // Testing long unbreakable and unencodable header
+ vmime::relay r;
+ r.parse(
+ " from User (Ee9GMqZQ8t7IQwftfAFHd2KyScCYRrFSJ50tKEoXv2bVCG4HcPU80GGWiFabAvG77FekpGgF1h@[127.0.0.1]) by servername.hostname.com\n\t"
+ "with esmtp id 1NGTS9-2C0sqG0; Fri, 4 Dec 2009 09:23:49 +0100"
+ );
+
+ VASSERT_EQ(
+ "received.long",
+ "from User\r\n (Ee9GMqZQ8t7IQwftfAFHd2KyScCYRrFSJ50tKEoXv2bVCG4HcPU80GGWiFabAvG77FekpGgF1h@[127.0.0.1])\r\n by servername.hostname.com with esmtp id 1NGTS9-2C0sqG0; Fri, 4 Dec 2009\r\n 09:23:49 +0100",
+ r.generate(78)
+ );
+ }
+
+ void testBugFix20110511() {
+
+ /*
+
+ Using the latest version of vmime (0.9.1), encoding the following string: Jean
+ Gwenaël Dutourd will result in:
+ Jean =?utf-8?Q?Gwena=C3=ABl_?= Dutourd
+ However, decoding this will result in Jean Gwenaël Dutourd (notice two spaces
+ between the last 2 words). The encoder adds a _ after the second word, but
+ since the last word is not encoded, the space between them is not ignored, and
+ is decoded into an additional space.
+
+ See: http://sourceforge.net/projects/vmime/forums/forum/237357/topic/4531365
+
+ */
+
+ const std::string DECODED_TEXT = "Jean Gwenaël Dutourd";
+ const std::string ENCODED_TEXT = "Jean =?utf-8?Q?Gwena=C3=ABl?= Dutourd";
+
+ // Encode
+ VASSERT_EQ(
+ "encode",
+ ENCODED_TEXT,
+ vmime::text::newFromString(DECODED_TEXT, vmime::charset("utf-8"))->generate()
+ );
+
+ // Decode
+ vmime::text t;
+ t.parse(ENCODED_TEXT);
+
+ // -- words
+ std::ostringstream oss; oss << t;
+ VASSERT_EQ(
+ "decode1",
+ "[text: [[word: charset=us-ascii, buffer=Jean ],"
+ "[word: charset=utf-8, buffer=Gwenaël],"
+ "[word: charset=us-ascii, buffer= Dutourd]]]",
+ oss.str()
+ );
+
+ // -- getWholeBuffer
+ VASSERT_EQ("decode2", DECODED_TEXT, t.getWholeBuffer());
+ }
+
+ void testInternationalizedEmail_specialChars() {
+
+ vmime::generationContext ctx(vmime::generationContext::getDefaultContext());
+ ctx.setInternationalizedEmailSupport(true);
+
+ vmime::generationContext::switcher <vmime::generationContext> contextSwitcher(ctx);
+
+ // Special sequence/chars should still be encoded
+ VASSERT_EQ(
+ "1",
+ "=?us-ascii?Q?Test=3D=3Frfc2047_sequence?=",
+ vmime::word("Test=?rfc2047 sequence", vmime::charset("us-ascii")).generate()
+ );
+
+ VASSERT_EQ(
+ "2",
+ "=?us-ascii?Q?Line_One=0ALine_Two?=",
+ vmime::word("Line One\nLine Two", vmime::charset("us-ascii")).generate()
+ );
+ }
+
+ void testInternationalizedEmail_UTF8() {
+
+ vmime::generationContext ctx(vmime::generationContext::getDefaultContext());
+ ctx.setInternationalizedEmailSupport(true);
+
+ vmime::generationContext::switcher <vmime::generationContext> contextSwitcher(ctx);
+
+ // Already UTF-8 encoded text should be left as is
+ VASSERT_EQ(
+ "1", "Achim Br\xc3\xa4ndt",
+ vmime::word("Achim Br\xc3\xa4ndt", vmime::charset("utf-8")).generate()
+ );
+ }
+
+ void testInternationalizedEmail_nonUTF8() {
+
+ vmime::generationContext ctx(vmime::generationContext::getDefaultContext());
+ ctx.setInternationalizedEmailSupport(true);
+
+ vmime::generationContext::switcher <vmime::generationContext> contextSwitcher(ctx);
+
+ // Non UTF-8 encoded text should first be converted to UTF-8
+ VASSERT_EQ(
+ "1", "Achim Br\xc3\xa4ndt",
+ vmime::word("Achim Br\xe4ndt", vmime::charset("iso-8859-1")).generate()
+ );
+ }
+
+ void testInternationalizedEmail_folding() {
+
+ vmime::generationContext ctx(vmime::generationContext::getDefaultContext());
+ ctx.setInternationalizedEmailSupport(true);
+
+ vmime::generationContext::switcher <vmime::generationContext> contextSwitcher(ctx);
+
+ // RFC-2047 encoding must be performed, as line folding is needed
+ vmime::word w1("01234567890123456789\xc3\xa0x012345678901234567890123456789"
+ "01234567890123456789\xc3\xa0x012345678901234567890123456789", vmime::charset("utf-8"));
+
+ VASSERT_EQ(
+ "1",
+ "=?utf-8?Q?01234567890123456789=C3=A0x01234567890?=\r\n"
+ " =?utf-8?Q?1234567890123456789012345678901234567?=\r\n"
+ " =?utf-8?Q?89=C3=A0x0123456789012345678901234567?=\r\n"
+ " =?utf-8?Q?89?=",
+ w1.generate(50)
+ );
+
+ // RFC-2047 encoding will not be forced, as words can be wrapped in a new line
+ vmime::word w2("bla bla bla This is some '\xc3\xa0\xc3\xa7' UTF-8 encoded text", vmime::charset("utf-8"));
+
+ VASSERT_EQ(
+ "2",
+ "bla bla bla This is\r\n"
+ " some '\xc3\xa0\xc3\xa7' UTF-8\r\n"
+ " encoded text",
+ w2.generate(20)
+ );
+ }
+
+ void testInternationalizedEmail_whitespace() {
+
+ // Sanity checks for running this test
+ {
+ vmime::text t;
+ t.parse("=?utf-8?Q?Adquisi=C3=B3n?= de Laptop y celular");
+
+ VASSERT_EQ("parse", "Adquisión de Laptop y celular", t.getWholeBuffer());
+ }
+
+ {
+ vmime::text t("Adquisi\xc3\xb3n de Laptop y celular", vmime::charset("UTF-8"));
+
+ VASSERT_EQ("generate", "=?UTF-8?Q?Adquisi=C3=B3n?= de Laptop y celular", t.generate());
+ }
+
+ // Ensure a whitespace is added between encoded words in intl email support enabled
+ {
+ vmime::text t;
+ t.parse("=?utf-8?Q?Adquisi=C3=B3n?= de Laptop y celular");
+
+ std::ostringstream oss;
+ vmime::utility::outputStreamAdapter ossAdapter(oss);
+ vmime::generationContext gctx(vmime::generationContext::getDefaultContext());
+ gctx.setInternationalizedEmailSupport(true);
+ t.generate(gctx, ossAdapter);
+
+ VASSERT_EQ("generate", "Adquisi\xc3\xb3n de Laptop y celular", oss.str());
+ }
+
+ {
+ vmime::text t;
+ t.parse("=?utf-8?Q?Adquisi=C3=B3n?= de Laptop =?utf-8?Q?y?= celular");
+
+ std::ostringstream oss;
+ vmime::utility::outputStreamAdapter ossAdapter(oss);
+ vmime::generationContext gctx(vmime::generationContext::getDefaultContext());
+ gctx.setInternationalizedEmailSupport(true);
+ t.generate(gctx, ossAdapter);
+
+ VASSERT_EQ("generate", "Adquisi\xc3\xb3n de Laptop y celular", oss.str());
+ }
+
+ {
+ vmime::text t;
+ t.parse("=?utf-8?Q?Adquisi=C3=B3n?= de Laptop =?utf-8?Q?y_celular?=");
+
+ std::ostringstream oss;
+ vmime::utility::outputStreamAdapter ossAdapter(oss);
+ vmime::generationContext gctx(vmime::generationContext::getDefaultContext());
+ gctx.setInternationalizedEmailSupport(true);
+ t.generate(gctx, ossAdapter);
+
+ VASSERT_EQ("generate", "Adquisi\xc3\xb3n de Laptop y celular", oss.str());
+ }
+
+ // Ensure no whitespace is added with non-encoded words
+ {
+ vmime::text t;
+ t.parse("Laptop y celular");
+
+ std::ostringstream oss;
+ vmime::utility::outputStreamAdapter ossAdapter(oss);
+ vmime::generationContext gctx(vmime::generationContext::getDefaultContext());
+ gctx.setInternationalizedEmailSupport(true);
+ t.generate(gctx, ossAdapter);
+
+ VASSERT_EQ("generate", "Laptop y celular", oss.str());
+ }
+
+ {
+ vmime::text t;
+ t.parse("=?utf-8?Q?Laptop_y_celular?=");
+
+ std::ostringstream oss;
+ vmime::utility::outputStreamAdapter ossAdapter(oss);
+ vmime::generationContext gctx(vmime::generationContext::getDefaultContext());
+ gctx.setInternationalizedEmailSupport(true);
+ t.generate(gctx, ossAdapter);
+
+ VASSERT_EQ("generate", "Laptop y celular", oss.str());
+ }
+ }
+
+ void testWronglyPaddedB64Words() {
+
+ vmime::text outText;
+
+ vmime::text::decodeAndUnfold("=?utf-8?B?5Lit5?=\n =?utf-8?B?paH?=", &outText);
+
+ VASSERT_EQ(
+ "1",
+ "\xe4\xb8\xad\xe6\x96\x87",
+ outText.getConvertedText(vmime::charset("utf-8"))
+ );
+
+ vmime::text::decodeAndUnfold("=?utf-8?B?5Lit5p?=\n =?utf-8?B?aH?=", &outText);
+
+ VASSERT_EQ(
+ "2",
+ "\xe4\xb8\xad\xe6\x96\x87",
+ outText.getConvertedText(vmime::charset("utf-8"))
+ );
+
+ vmime::text::decodeAndUnfold("=?utf-8?B?5Lit5pa?=\n =?utf-8?B?H?=", &outText);
+
+ VASSERT_EQ(
+ "3",
+ "\xe4\xb8\xad\xe6\x96\x87",
+ outText.getConvertedText(vmime::charset("utf-8"))
+ );
+ }
+
+ // Ensure that words which encode a non-integral number of characters
+ // are correctly decoded.
+ void testFixBrokenWords() {
+
+ vmime::text outText;
+
+ vmime::charsetConverterOptions opts;
+ opts.silentlyReplaceInvalidSequences = false; // just to be sure that broken words are actually fixed
+
+ // Test case 1
+ vmime::text::decodeAndUnfold(
+ "=?utf-8?Q?Gwena=C3?="
+ "=?utf-8?Q?=ABl?=",
+ &outText
+ );
+
+ VASSERT_EQ("1.1", 1, outText.getWordCount());
+ VASSERT_EQ("1.2", "Gwena\xc3\xabl", outText.getWordAt(0)->getBuffer());
+ VASSERT_EQ("1.3", vmime::charset("utf-8"), outText.getWordAt(0)->getCharset());
+
+ // Test case 2
+ vmime::text::decodeAndUnfold(
+ "=?utf-8?B?5Lit6Yu85qmf5qKw6JGj5LqL5pyDMTAz5bm056ysMDXlsYbn?="
+ "=?utf-8?B?rKwwN+asoeitsOeoiw==?=",
+ &outText
+ );
+
+ VASSERT_EQ("2.1", 1, outText.getWordCount());
+ VASSERT_EQ("2.2", "\xe4\xb8\xad\xe9\x8b\xbc\xe6\xa9\x9f\xe6\xa2\xb0"
+ "\xe8\x91\xa3\xe4\xba\x8b\xe6\x9c\x83\x31\x30\x33\xe5\xb9\xb4"
+ "\xe7\xac\xac\x30\x35\xe5\xb1\x86\xe7\xac\xac\x30\x37\xe6\xac"
+ "\xa1\xe8\xad\xb0\xe7\xa8\x8b", outText.getWordAt(0)->getBuffer());
+ VASSERT_EQ("2.3", vmime::charset("utf-8"), outText.getWordAt(0)->getCharset());
+
+ // Test case 3 (a character spanning over 3 words: 'を' = E3 82 92)
+ vmime::text::decodeAndUnfold(
+ "=?utf-8?Q?abc=E3?="
+ "=?utf-8?Q?=82?="
+ "=?utf-8?Q?=92xyz?=",
+ &outText
+ );
+
+ VASSERT_EQ("3.1", 1, outText.getWordCount());
+ VASSERT_EQ("3.2", "abc\xe3\x82\x92xyz", outText.getWordAt(0)->getBuffer());
+ VASSERT_EQ("3.3", vmime::charset("utf-8"), outText.getWordAt(0)->getCharset());
+
+ // Test case 4 (remains invalid)
+ vmime::text::decodeAndUnfold(
+ "=?utf-8?Q?abc=E3?="
+ "=?utf-8?Q?=82?="
+ "=?utf-8?Q?xy?="
+ "=?utf-8?Q?z?=",
+ &outText
+ );
+
+ VASSERT_EQ("4.1", 2, outText.getWordCount());
+ VASSERT_EQ("4.2", "abc", outText.getWordAt(0)->getBuffer());
+ VASSERT_EQ("4.3", vmime::charset("utf-8"), outText.getWordAt(0)->getCharset());
+ VASSERT_EQ("4.4", "\xe3\x82xyz", outText.getWordAt(1)->getBuffer());
+ VASSERT_EQ("4.5", vmime::charset("utf-8"), outText.getWordAt(1)->getCharset());
+
+ // Test case 5 (remains partially invalid)
+ vmime::text::decodeAndUnfold(
+ "=?utf-8?Q?abc=E3?="
+ "=?utf-8?Q?=82?="
+ "=?utf-8?Q?\x92xy?="
+ "=?utf-8?Q?z\xc3?=",
+ &outText
+ );
+
+ VASSERT_EQ("5.1", 2, outText.getWordCount());
+ VASSERT_EQ("5.2", "abc\xe3\x82\x92xyz", outText.getWordAt(0)->getBuffer());
+ VASSERT_EQ("5.3", vmime::charset("utf-8"), outText.getWordAt(0)->getCharset());
+ VASSERT_EQ("5.4", "\xc3", outText.getWordAt(1)->getBuffer());
+ VASSERT_EQ("5.5", vmime::charset("utf-8"), outText.getWordAt(1)->getCharset());
+ }
+
+ void testUnknownCharset() {
+
+ vmime::text t;
+ vmime::text::decodeAndUnfold("=?gb2312?B?wdaRY8PA?=", &t);
+
+ VASSERT_EQ("1.1", 1, t.getWordCount());
+ VASSERT_EQ("1.2", "\xc1\xd6\x91\x63\xc3\xc0", t.getWordAt(0)->getBuffer());
+ VASSERT_EQ("1.3", vmime::charset("gb2312"), t.getWordAt(0)->getCharset());
+
+
+
+ vmime::parsingContext ctx;
+
+ const vmime::string hfieldBuffer = "From: '=?gb2312?B?wdaRY8PA?=' <a.b@c.de>";
+
+ vmime::shared_ptr <vmime::headerField> hfield =
+ vmime::headerField::parseNext(ctx, hfieldBuffer, 0, hfieldBuffer.size());
+
+ vmime::shared_ptr <vmime::mailbox> hvalue =
+ hfield->getValue <vmime::mailbox>();
+
+ VASSERT_EQ("2.1", 3, hvalue->getName().getWordCount());
+ VASSERT_EQ("2.2", "'", hvalue->getName().getWordAt(0)->getBuffer());
+ VASSERT_EQ("2.3", vmime::charset("us-ascii"), hvalue->getName().getWordAt(0)->getCharset());
+ VASSERT_EQ("2.4", "\xc1\xd6\x91\x63\xc3\xc0", hvalue->getName().getWordAt(1)->getBuffer());
+ VASSERT_EQ("2.5", vmime::charset("gb2312"), hvalue->getName().getWordAt(1)->getCharset());
+ VASSERT_EQ("2.6", "'", hvalue->getName().getWordAt(2)->getBuffer());
+ VASSERT_EQ("2.7", vmime::charset("us-ascii"), hvalue->getName().getWordAt(2)->getCharset());
+ }
+
+VMIME_TEST_SUITE_END
diff --git a/vmime-master/tests/parser/wordEncoderTest.cpp b/vmime-master/tests/parser/wordEncoderTest.cpp
new file mode 100644
index 0000000..08d34aa
--- /dev/null
+++ b/vmime-master/tests/parser/wordEncoderTest.cpp
@@ -0,0 +1,174 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "tests/testUtils.hpp"
+
+#include "vmime/wordEncoder.hpp"
+
+
+VMIME_TEST_SUITE_BEGIN(wordEncoderTest)
+
+ VMIME_TEST_LIST_BEGIN
+ VMIME_TEST(testGetNextChunk)
+ VMIME_TEST(testGetNextChunk_integral)
+ VMIME_TEST(testIsEncodingNeeded_ascii)
+ VMIME_TEST(testIsEncodingNeeded_withLanguage)
+ VMIME_TEST(testIsEncodingNeeded_specialChars)
+ VMIME_TEST(testGuessBestEncoding_QP)
+ VMIME_TEST(testGuessBestEncoding_B64)
+ VMIME_TEST(testEncodeQP_RFC2047)
+ VMIME_TEST_LIST_END
+
+
+ void testGetNextChunk() {
+
+ // An integral number of characters should be encoded
+ vmime::wordEncoder we(
+ "bufferfoobarbaz",
+ vmime::charset("utf-8"),
+ vmime::wordEncoder::ENCODING_AUTO
+ );
+
+ VASSERT_EQ("1", "buffer", we.getNextChunk(6));
+ VASSERT_EQ("2", "foo", we.getNextChunk(3));
+ VASSERT_EQ("3", "barbaz", we.getNextChunk(10));
+ }
+
+ void testGetNextChunk_integral() {
+
+ // An integral number of characters should be encoded
+ vmime::wordEncoder we(
+ "buffer\xc3\xa0plop",
+ vmime::charset("utf-8"),
+ vmime::wordEncoder::ENCODING_AUTO
+ );
+
+ VASSERT_EQ("1", "buffer=C3=A0", we.getNextChunk(7));
+ VASSERT_EQ("2", "plop", we.getNextChunk(10));
+ }
+
+ void testIsEncodingNeeded_ascii() {
+
+ vmime::generationContext ctx(vmime::generationContext::getDefaultContext());
+ ctx.setInternationalizedEmailSupport(false);
+
+ VASSERT_FALSE(
+ "ascii",
+ vmime::wordEncoder::isEncodingNeeded(
+ ctx, "ASCII-only buffer", vmime::charset("utf-8"), ""
+ )
+ );
+
+ VASSERT_TRUE(
+ "non-ascii",
+ vmime::wordEncoder::isEncodingNeeded(
+ ctx, "Buffer with some UTF-8 '\xc3\xa0'", vmime::charset("utf-8"), ""
+ )
+ );
+ }
+
+ void testIsEncodingNeeded_withLanguage() {
+
+ VASSERT_TRUE(
+ "ascii",
+ vmime::wordEncoder::isEncodingNeeded(
+ vmime::generationContext::getDefaultContext(),
+ "ASCII-only buffer",
+ vmime::charset("utf-8"),
+ "en"
+ )
+ );
+ }
+
+ void testIsEncodingNeeded_specialChars() {
+
+ VASSERT_TRUE(
+ "rfc2047",
+ vmime::wordEncoder::isEncodingNeeded(
+ vmime::generationContext::getDefaultContext(),
+ "foo bar =? foo bar",
+ vmime::charset("us-ascii"),
+ ""
+ )
+ );
+
+ VASSERT_TRUE(
+ "new line 1",
+ vmime::wordEncoder::isEncodingNeeded(
+ vmime::generationContext::getDefaultContext(),
+ "foo bar \n foo bar",
+ vmime::charset("us-ascii"),
+ ""
+ )
+ );
+
+ VASSERT_TRUE(
+ "new line 2",
+ vmime::wordEncoder::isEncodingNeeded(
+ vmime::generationContext::getDefaultContext(),
+ "foo bar \r foo bar",
+ vmime::charset("us-ascii"),
+ ""
+ )
+ );
+ }
+
+ void testGuessBestEncoding_QP() {
+
+ VASSERT_EQ(
+ "1",
+ vmime::wordEncoder::ENCODING_QP,
+ vmime::wordEncoder::guessBestEncoding("ASCII only buffer", vmime::charset("us-ascii"))
+ );
+ }
+
+ void testGuessBestEncoding_B64() {
+
+ // >= 40% non-ASCII => Base64...
+ VASSERT_EQ(
+ "1",
+ vmime::wordEncoder::ENCODING_B64,
+ vmime::wordEncoder::guessBestEncoding("xxxxx\xc3\xa0\xc3\xa0", vmime::charset("utf-8"))
+ );
+
+ // ...else Quoted-Printable
+ VASSERT_EQ(
+ "2",
+ vmime::wordEncoder::ENCODING_QP,
+ vmime::wordEncoder::guessBestEncoding("xxxxxx\xc3\xa0\xc3\xa0", vmime::charset("utf-8"))
+ );
+ }
+
+ void testEncodeQP_RFC2047() {
+
+ // When Quoted-Printable is used, it should be RFC-2047 QP encoding
+ vmime::wordEncoder we(
+ "buffer\xc3\xa0 foo_bar",
+ vmime::charset("utf-8"),
+ vmime::wordEncoder::ENCODING_AUTO
+ );
+
+ VASSERT_EQ("1", "buffer=C3=A0_foo=5Fbar", we.getNextChunk(100));
+ }
+
+VMIME_TEST_SUITE_END