ferencd@0: // ferencd@0: // VMime library (http://www.vmime.org) ferencd@0: // Copyright (C) 2002-2013 Vincent Richard ferencd@0: // ferencd@0: // This program is free software; you can redistribute it and/or ferencd@0: // modify it under the terms of the GNU General Public License as ferencd@0: // published by the Free Software Foundation; either version 3 of ferencd@0: // the License, or (at your option) any later version. ferencd@0: // ferencd@0: // This program is distributed in the hope that it will be useful, ferencd@0: // but WITHOUT ANY WARRANTY; without even the implied warranty of ferencd@0: // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ferencd@0: // General Public License for more details. ferencd@0: // ferencd@0: // You should have received a copy of the GNU General Public License along ferencd@0: // with this program; if not, write to the Free Software Foundation, Inc., ferencd@0: // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. ferencd@0: // ferencd@0: // Linking this library statically or dynamically with other modules is making ferencd@0: // a combined work based on this library. Thus, the terms and conditions of ferencd@0: // the GNU General Public License cover the whole combination. ferencd@0: // ferencd@0: ferencd@0: #include "tests/testUtils.hpp" ferencd@0: ferencd@0: #include ferencd@0: #include ferencd@0: ferencd@0: ferencd@0: VMIME_TEST_SUITE_BEGIN(textTest) ferencd@0: ferencd@0: VMIME_TEST_LIST_BEGIN ferencd@0: VMIME_TEST(testConstructors) ferencd@0: VMIME_TEST(testCopy) ferencd@0: VMIME_TEST(testNewFromString) ferencd@0: VMIME_TEST(testDisplayForm) ferencd@0: VMIME_TEST(testParse) ferencd@0: VMIME_TEST(testGenerate) ferencd@0: ferencd@0: VMIME_TEST(testWordConstructors) ferencd@0: VMIME_TEST(testWordParse) ferencd@0: VMIME_TEST(testWordGenerate) ferencd@0: VMIME_TEST(testWordGenerateSpace) ferencd@0: VMIME_TEST(testWordGenerateSpace2) ferencd@0: VMIME_TEST(testWordGenerateMultiBytes) ferencd@0: VMIME_TEST(testWordGenerateQuote) ferencd@0: VMIME_TEST(testWordGenerateSpecialCharsets) ferencd@0: VMIME_TEST(testWordGenerateSpecials) ferencd@0: ferencd@0: VMIME_TEST(testWhitespace) ferencd@0: VMIME_TEST(testWhitespaceMBox) ferencd@0: ferencd@0: VMIME_TEST(testFoldingAscii) ferencd@0: VMIME_TEST(testForcedNonEncoding) ferencd@0: ferencd@0: VMIME_TEST(testBugFix20110511) ferencd@0: ferencd@0: VMIME_TEST(testInternationalizedEmail_specialChars) ferencd@0: VMIME_TEST(testInternationalizedEmail_UTF8) ferencd@0: VMIME_TEST(testInternationalizedEmail_nonUTF8) ferencd@0: VMIME_TEST(testInternationalizedEmail_folding) ferencd@0: VMIME_TEST_LIST_END ferencd@0: ferencd@0: ferencd@0: static const vmime::string getDisplayText(const vmime::text& t) ferencd@0: { ferencd@0: return t.getWholeBuffer(); ferencd@0: } ferencd@0: ferencd@0: static const vmime::string cleanGeneratedWords(const std::string& str) ferencd@0: { ferencd@0: std::istringstream iss(str); ferencd@0: ferencd@0: std::string res; ferencd@0: std::string x; ferencd@0: ferencd@0: while (std::getline(iss, x)) ferencd@0: res += vmime::utility::stringUtils::trim(x); ferencd@0: ferencd@0: return res; ferencd@0: } ferencd@0: ferencd@0: ferencd@0: void setUp() ferencd@0: { ferencd@0: // Set the global C and C++ locale to the user-configured locale. ferencd@0: // The locale should use UTF-8 encoding for these tests to run successfully. ferencd@0: try ferencd@0: { ferencd@0: std::locale::global(std::locale("")); ferencd@0: } ferencd@0: catch (std::exception &) ferencd@0: { ferencd@0: std::setlocale(LC_ALL, ""); ferencd@0: } ferencd@0: } ferencd@0: ferencd@0: void tearDown() ferencd@0: { ferencd@0: // Restore default locale ferencd@0: std::locale::global(std::locale("C")); ferencd@0: } ferencd@0: ferencd@0: ferencd@0: void testConstructors() ferencd@0: { ferencd@0: vmime::text t1; ferencd@0: ferencd@0: VASSERT_EQ("1.1", 0, t1.getWordCount()); ferencd@0: ferencd@0: vmime::text t2("Test\xa9\xc3"); ferencd@0: ferencd@0: VASSERT_EQ("2.1", 1, t2.getWordCount()); ferencd@0: VASSERT_EQ("2.2", "Test\xa9\xc3", t2.getWordAt(0)->getBuffer()); ferencd@0: VASSERT_EQ("2.3", vmime::charset::getLocalCharset(), t2.getWordAt(0)->getCharset()); ferencd@0: ferencd@0: vmime::text t3("Test\xa9\xc3", vmime::charset(vmime::charsets::ISO8859_13)); ferencd@0: ferencd@0: VASSERT_EQ("3.1", 1, t3.getWordCount()); ferencd@0: VASSERT_EQ("3.2", "Test\xa9\xc3", t3.getWordAt(0)->getBuffer()); ferencd@0: VASSERT_EQ("3.3", vmime::charset(vmime::charsets::ISO8859_13), t3.getWordAt(0)->getCharset()); ferencd@0: ferencd@0: vmime::word w1("Test", vmime::charset(vmime::charsets::UTF_8)); ferencd@0: vmime::text t4(w1); ferencd@0: ferencd@0: VASSERT_EQ("4.1", 1, t4.getWordCount()); ferencd@0: VASSERT_EQ("4.2", w1.getBuffer(), t4.getWordAt(0)->getBuffer()); ferencd@0: VASSERT_EQ("4.3", w1.getCharset(), t4.getWordAt(0)->getCharset()); ferencd@0: ferencd@0: vmime::word w2("Other", vmime::charset(vmime::charsets::US_ASCII)); ferencd@0: t4.appendWord(vmime::make_shared (w2)); ferencd@0: ferencd@0: vmime::text t5(t4); ferencd@0: ferencd@0: VASSERT_EQ("5.1", 2, t5.getWordCount()); ferencd@0: VASSERT_EQ("5.2", w1.getBuffer(), t5.getWordAt(0)->getBuffer()); ferencd@0: VASSERT_EQ("5.3", w1.getCharset(), t5.getWordAt(0)->getCharset()); ferencd@0: VASSERT_EQ("5.4", w2.getBuffer(), t5.getWordAt(1)->getBuffer()); ferencd@0: VASSERT_EQ("5.5", w2.getCharset(), t5.getWordAt(1)->getCharset()); ferencd@0: } ferencd@0: ferencd@0: void testCopy() ferencd@0: { ferencd@0: vmime::text t1("Test: \xa9\xc3"); ferencd@0: ferencd@0: VASSERT("operator==", t1 == t1); ferencd@0: VASSERT("clone", *vmime::clone(t1) == t1); ferencd@0: ferencd@0: vmime::text t2; ferencd@0: t2.copyFrom(t1); ferencd@0: ferencd@0: VASSERT("copyFrom", t1 == t2); ferencd@0: } ferencd@0: ferencd@0: void testNewFromString() ferencd@0: { ferencd@0: vmime::string s1 = "only ASCII characters"; ferencd@0: vmime::charset c1("test"); ferencd@0: vmime::text t1; ferencd@0: ferencd@0: t1.createFromString(s1, c1); ferencd@0: ferencd@0: VASSERT_EQ("1.1", 1, t1.getWordCount()); ferencd@0: VASSERT_EQ("1.2", s1, t1.getWordAt(0)->getBuffer()); ferencd@0: VASSERT_EQ("1.3", vmime::charset(vmime::charsets::US_ASCII), t1.getWordAt(0)->getCharset()); ferencd@0: ferencd@0: vmime::string s2_1 = "some ASCII characters and special chars: "; ferencd@0: vmime::string s2_2 = "\xf1\xf2\xf3\xf4 "; ferencd@0: vmime::string s2_3 = "and then more ASCII chars."; ferencd@0: vmime::string s2 = s2_1 + s2_2 + s2_3; ferencd@0: vmime::charset c2("test"); ferencd@0: vmime::text t2; ferencd@0: ferencd@0: t2.createFromString(s2, c2); ferencd@0: ferencd@0: VASSERT_EQ("2.1", 3, t2.getWordCount()); ferencd@0: VASSERT_EQ("2.2", "some ASCII characters and special chars: ", t2.getWordAt(0)->getBuffer()); ferencd@0: VASSERT_EQ("2.3", vmime::charset(vmime::charsets::US_ASCII), t2.getWordAt(0)->getCharset()); ferencd@0: VASSERT_EQ("2.4", "\xf1\xf2\xf3\xf4", t2.getWordAt(1)->getBuffer()); ferencd@0: VASSERT_EQ("2.5", c2, t2.getWordAt(1)->getCharset()); ferencd@0: VASSERT_EQ("2.6", "and then more ASCII chars.", t2.getWordAt(2)->getBuffer()); ferencd@0: VASSERT_EQ("2.7", vmime::charset(vmime::charsets::US_ASCII), t2.getWordAt(2)->getCharset()); ferencd@0: } ferencd@0: ferencd@0: static const vmime::string parseText(const vmime::string& buffer) ferencd@0: { ferencd@0: vmime::text t; ferencd@0: t.parse(buffer); ferencd@0: ferencd@0: std::ostringstream oss; ferencd@0: oss << t; ferencd@0: ferencd@0: return (oss.str()); ferencd@0: } ferencd@0: ferencd@0: void testParse() ferencd@0: { ferencd@0: // From RFC-2047 ferencd@0: VASSERT_EQ("1", "[text: [[word: charset=US-ASCII, buffer=Keith Moore]]]", ferencd@0: parseText("=?US-ASCII?Q?Keith_Moore?=")); ferencd@0: ferencd@0: VASSERT_EQ("2", "[text: [[word: charset=ISO-8859-1, buffer=Keld J\xf8rn Simonsen]]]", ferencd@0: parseText("=?ISO-8859-1?Q?Keld_J=F8rn_Simonsen?=")); ferencd@0: ferencd@0: VASSERT_EQ("3", "[text: [[word: charset=ISO-8859-1, buffer=Andr\xe9]," \ ferencd@0: "[word: charset=us-ascii, buffer= Pirard]]]", ferencd@0: parseText("=?ISO-8859-1?Q?Andr=E9?= Pirard")); ferencd@0: ferencd@0: VASSERT_EQ("4", "[text: [[word: charset=ISO-8859-1, buffer=If you can read this yo]," \ ferencd@0: "[word: charset=ISO-8859-2, buffer=u understand the example.]]]", ferencd@0: parseText("=?ISO-8859-1?B?SWYgeW91IGNhbiByZWFkIHRoaXMgeW8=?=\r\n " \ ferencd@0: "=?ISO-8859-2?B?dSB1bmRlcnN0YW5kIHRoZSBleGFtcGxlLg==?=")); ferencd@0: ferencd@0: // Bugfix: in "=?charset?q?=XX=YY?=", the "?=" finish ferencd@0: // sequence was not correctly found (should be the one ferencd@0: // after '=YY' and not the one after '?q'). ferencd@0: VASSERT_EQ("5", "[text: [[word: charset=abc, buffer=\xe9\xe9]]]", ferencd@0: parseText("=?abc?q?=E9=E9?=")); ferencd@0: ferencd@0: // Question marks (?) in the middle of the string ferencd@0: VASSERT_EQ("6", "[text: [[word: charset=iso-8859-1, buffer=Know wh\xe4t? It works!]]]", ferencd@0: parseText("=?iso-8859-1?Q?Know_wh=E4t?_It_works!?=")); ferencd@0: ferencd@0: // With language specifier ferencd@0: VASSERT_EQ("7", "[text: [[word: charset=US-ASCII, buffer=Keith Moore, lang=EN]]]", ferencd@0: parseText("=?US-ASCII*EN?Q?Keith_Moore?=")); ferencd@0: } ferencd@0: ferencd@0: void testGenerate() ferencd@0: { ferencd@0: // TODO ferencd@0: ferencd@0: // With language specifier ferencd@0: vmime::word wlang1("Émeline", vmime::charset("UTF-8"), "FR"); ferencd@0: VASSERT_EQ("lang1", "=?UTF-8*FR?Q?=C3=89meline?=", wlang1.generate()); ferencd@0: ferencd@0: vmime::word wlang2("Keith Moore", vmime::charset("US-ASCII"), "EN"); ferencd@0: VASSERT_EQ("lang2", "=?US-ASCII*EN?Q?Keith_Moore?=", wlang2.generate()); ferencd@0: } ferencd@0: ferencd@0: void testDisplayForm() ferencd@0: { ferencd@0: #define DISPLAY_FORM(x) getDisplayText(*vmime::text::decodeAndUnfold(x)) ferencd@0: ferencd@0: // From RFC-2047 ferencd@0: VASSERT_EQ("1", "a", DISPLAY_FORM("=?ISO-8859-1?Q?a?=")); ferencd@0: VASSERT_EQ("2", "a b", DISPLAY_FORM("=?ISO-8859-1?Q?a?= b")); ferencd@0: VASSERT_EQ("3", "ab", DISPLAY_FORM("=?ISO-8859-1?Q?a?= =?ISO-8859-1?Q?b?=")); ferencd@0: VASSERT_EQ("4", "ab", DISPLAY_FORM("=?ISO-8859-1?Q?a?= \t =?ISO-8859-1?Q?b?=")); ferencd@0: VASSERT_EQ("5", "ab", DISPLAY_FORM("=?ISO-8859-1?Q?a?= \r\n \t =?ISO-8859-1?Q?b?=")); ferencd@0: VASSERT_EQ("6", "a b", DISPLAY_FORM("=?ISO-8859-1?Q?a_b?=")); ferencd@0: VASSERT_EQ("7", "a b", DISPLAY_FORM("=?ISO-8859-1?Q?a?= =?ISO-8859-2?Q?_b?=")); ferencd@0: ferencd@0: // Some more tests... ferencd@0: VASSERT_EQ("8", "a b", DISPLAY_FORM(" a =?ISO-8859-1?Q?b?= ")); ferencd@0: VASSERT_EQ("9", "a b ", DISPLAY_FORM(" \t =?ISO-8859-1?Q?a?= b ")); ferencd@0: VASSERT_EQ("10", "a b", DISPLAY_FORM(" a\r\n\t b")); ferencd@0: ferencd@0: VASSERT_EQ("11", "a b c", DISPLAY_FORM("a =?ISO-8859-1?Q?b?= c")); ferencd@0: VASSERT_EQ("12", "a b c ", DISPLAY_FORM("a =?ISO-8859-1?Q?b?= c ")); ferencd@0: VASSERT_EQ("13", "a b c ", DISPLAY_FORM(" a =?ISO-8859-1?Q?b?= c ")); ferencd@0: VASSERT_EQ("14", "a b c d", DISPLAY_FORM("a =?ISO-8859-1?Q?b?= c =?ISO-8859-1?Q?d?= ")); ferencd@0: VASSERT_EQ("15", "a b c d e", DISPLAY_FORM("a =?ISO-8859-1?Q?b?= c =?ISO-8859-1?Q?d?= e")); ferencd@0: ferencd@0: // Whitespaces and multiline ferencd@0: 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")); ferencd@0: ferencd@0: #undef DISPLAY_FORM ferencd@0: } ferencd@0: ferencd@0: void testWordConstructors() ferencd@0: { ferencd@0: VASSERT_EQ("1.1", vmime::charset::getLocalCharset(), vmime::word().getCharset()); ferencd@0: VASSERT_EQ("1.2", "", vmime::word().getBuffer()); ferencd@0: ferencd@0: VASSERT_EQ("2.1", vmime::charset::getLocalCharset(), vmime::word("foo").getCharset()); ferencd@0: VASSERT_EQ("2.2", "foo", vmime::word("foo").getBuffer()); ferencd@0: ferencd@0: VASSERT_EQ("3.1", "bar", vmime::word("foo", vmime::charset("bar")).getCharset().getName()); ferencd@0: VASSERT_EQ("3.2", "foo", vmime::word("foo", vmime::charset("bar")).getBuffer()); ferencd@0: } ferencd@0: ferencd@0: void testWordParse() ferencd@0: { ferencd@0: // Simple encoded word ferencd@0: vmime::word w1; ferencd@0: w1.parse("=?foo?q?bar=E9 baz?="); ferencd@0: ferencd@0: VASSERT_EQ("1.1", "foo", w1.getCharset().getName()); ferencd@0: VASSERT_EQ("1.2", "bar\xe9 baz", w1.getBuffer()); ferencd@0: ferencd@0: // Unencoded text ferencd@0: vmime::word w2; ferencd@0: w2.parse(" foo bar \tbaz..."); ferencd@0: ferencd@0: VASSERT_EQ("2.1", vmime::charset(vmime::charsets::US_ASCII), w2.getCharset()); ferencd@0: VASSERT_EQ("2.2", " foo bar \tbaz...", w2.getBuffer()); ferencd@0: ferencd@0: // Malformed word ferencd@0: vmime::word w3; ferencd@0: w3.parse("=?foo bar"); ferencd@0: ferencd@0: VASSERT_EQ("3.1", vmime::charset(vmime::charsets::US_ASCII), w3.getCharset()); ferencd@0: VASSERT_EQ("3.2", "=?foo bar", w3.getBuffer()); ferencd@0: ferencd@0: // Unknown encoding ferencd@0: vmime::word w4; ferencd@0: w4.parse("=?whatever?not_q_or_b?whatever?="); ferencd@0: ferencd@0: VASSERT_EQ("4.1", vmime::charset(vmime::charsets::US_ASCII), w4.getCharset()); ferencd@0: VASSERT_EQ("4.2", "=?whatever?not_q_or_b?whatever?=", w4.getBuffer()); ferencd@0: } ferencd@0: ferencd@0: void testWordGenerate() ferencd@0: { ferencd@0: VASSERT_EQ("1", "=?foo?Q?bar=E9_baz?=", ferencd@0: vmime::word("bar\xe9 baz", vmime::charset("foo")).generate()); ferencd@0: ferencd@0: VASSERT_EQ("2", "=?foo?B?8fLz9PU=?=", ferencd@0: vmime::word("\xf1\xf2\xf3\xf4\xf5", vmime::charset("foo")).generate()); ferencd@0: } ferencd@0: ferencd@0: void testWordGenerateSpace() ferencd@0: { ferencd@0: // No white-space between an unencoded word and a encoded one ferencd@0: VASSERT_EQ("1", "Bonjour =?utf-8?Q?Fran=C3=A7ois?=", ferencd@0: vmime::text::newFromString("Bonjour Fran\xc3\xa7ois", ferencd@0: vmime::charset("utf-8"))->generate()); ferencd@0: ferencd@0: // White-space between two encoded words ferencd@0: vmime::text txt; ferencd@0: txt.appendWord(vmime::make_shared ("\xc3\x89t\xc3\xa9", "utf-8")); ferencd@0: txt.appendWord(vmime::make_shared ("Fran\xc3\xa7ois", "utf-8")); ferencd@0: ferencd@0: const vmime::string decoded = "\xc3\x89t\xc3\xa9""Fran\xc3\xa7ois"; ferencd@0: const vmime::string encoded = "=?utf-8?B?w4l0w6k=?= =?utf-8?Q?Fran=C3=A7ois?="; ferencd@0: ferencd@0: // -- test encoding ferencd@0: VASSERT_EQ("2", encoded, txt.generate()); ferencd@0: ferencd@0: // -- ensure no space is added when decoding ferencd@0: vmime::text txt2; ferencd@0: txt2.parse(encoded, 0, encoded.length()); ferencd@0: ferencd@0: VASSERT_EQ("3", decoded, txt2.getWholeBuffer()); ferencd@0: ferencd@0: // -- test rencoding ferencd@0: VASSERT_EQ("4", encoded, txt2.generate()); ferencd@0: } ferencd@0: ferencd@0: void testWordGenerateSpace2() ferencd@0: { ferencd@0: // White-space between two encoded words (#2) ferencd@0: vmime::text txt; ferencd@0: txt.appendWord(vmime::make_shared ("Facture ", "utf-8")); ferencd@0: txt.appendWord(vmime::make_shared ("\xc3\xa0", "utf-8")); ferencd@0: txt.appendWord(vmime::make_shared (" envoyer ", "utf-8")); ferencd@0: txt.appendWord(vmime::make_shared ("\xc3\xa0", "utf-8")); ferencd@0: txt.appendWord(vmime::make_shared (" Martine", "utf-8")); ferencd@0: ferencd@0: const vmime::string decoded = "Facture ""\xc3\xa0"" envoyer ""\xc3\xa0"" Martine"; ferencd@0: const vmime::string encoded = "Facture =?utf-8?B?w6A=?= envoyer =?utf-8?B?w6A=?= Martine"; ferencd@0: ferencd@0: // -- test encoding ferencd@0: VASSERT_EQ("1", encoded, txt.generate()); ferencd@0: ferencd@0: // -- ensure no space is added when decoding ferencd@0: vmime::text txt2; ferencd@0: txt2.parse(encoded, 0, encoded.length()); ferencd@0: ferencd@0: VASSERT_EQ("2", decoded, txt2.getWholeBuffer()); ferencd@0: ferencd@0: // -- test rencoding ferencd@0: VASSERT_EQ("3", encoded, txt2.generate()); ferencd@0: } ferencd@0: ferencd@0: void testWordGenerateMultiBytes() ferencd@0: { ferencd@0: // Ensure we don't encode a non-integral number of characters ferencd@0: VASSERT_EQ("1", "=?utf-8?Q?aaa?==?utf-8?Q?=C3=A9?==?utf-8?Q?zzz?=", ferencd@0: cleanGeneratedWords(vmime::word("aaa\xc3\xa9zzz", vmime::charset("utf-8")).generate(16))); ferencd@0: ferencd@0: VASSERT_EQ("2", "=?utf-8?Q?aaa=C3=A9?==?utf-8?Q?zzz?=", ferencd@0: cleanGeneratedWords(vmime::word("aaa\xc3\xa9zzz", vmime::charset("utf-8")).generate(17))); ferencd@0: } ferencd@0: ferencd@0: void testWordGenerateQuote() ferencd@0: { ferencd@0: std::string str; ferencd@0: vmime::utility::outputStreamStringAdapter os(str); ferencd@0: ferencd@0: vmime::generationContext ctx; ferencd@0: ctx.setMaxLineLength(1000); ferencd@0: ferencd@0: // ASCII-only text is quotable ferencd@0: str.clear(); ferencd@0: vmime::word("Quoted text").generate(ctx, os, 0, NULL, vmime::text::QUOTE_IF_POSSIBLE, NULL); ferencd@0: VASSERT_EQ("1", "\"Quoted text\"", cleanGeneratedWords(str)); ferencd@0: ferencd@0: // Text with CR/LF is not quotable ferencd@0: str.clear(); ferencd@0: vmime::word("Non-quotable\ntext", "us-ascii").generate(ctx, os, 0, NULL, vmime::text::QUOTE_IF_POSSIBLE, NULL); ferencd@0: VASSERT_EQ("2", "=?us-ascii?Q?Non-quotable=0Atext?=", cleanGeneratedWords(str)); ferencd@0: ferencd@0: // Text with non-ASCII chars is not quotable ferencd@0: str.clear(); ferencd@0: vmime::word("Non-quotable text \xc3\xa9").generate(ctx, os, 0, NULL, vmime::text::QUOTE_IF_POSSIBLE, NULL); ferencd@0: VASSERT_EQ("3", "=?UTF-8?Q?Non-quotable_text_=C3=A9?=", cleanGeneratedWords(str)); ferencd@0: } ferencd@0: ferencd@0: void testWordGenerateSpecialCharsets() ferencd@0: { ferencd@0: // ISO-2022-JP only uses 7-bit chars but should be encoded in Base64 ferencd@0: VASSERT_EQ("1", "=?iso-2022-jp?B?XlskQiVRITwlPSVKJWshJiU9JVUlSCUmJSclIl5bKEI=?=", ferencd@0: cleanGeneratedWords(vmime::word("^[$B%Q!<%=%J%k!&%=%U%H%&%'%\"^[(B", ferencd@0: vmime::charset("iso-2022-jp")).generate(100))); ferencd@0: } ferencd@0: ferencd@0: void testWordGenerateSpecials() ferencd@0: { ferencd@0: // In RFC-2047, quotation marks (ASCII 22h) should be encoded ferencd@0: VASSERT_EQ("1", "=?UTF-8?Q?=22=C3=9Cml=C3=A4ute=22?=", ferencd@0: vmime::word("\x22\xC3\x9Cml\xC3\xA4ute\x22", vmime::charset("UTF-8")).generate()); ferencd@0: } ferencd@0: ferencd@0: void testWhitespace() ferencd@0: { ferencd@0: // Create ferencd@0: vmime::text text; ferencd@0: text.createFromString("Achim Br\xc3\xa4ndt", vmime::charsets::UTF_8); ferencd@0: ferencd@0: VASSERT_EQ("1", 2, text.getWordCount()); ferencd@0: VASSERT_EQ("2", "Achim ", text.getWordAt(0)->getBuffer()); ferencd@0: VASSERT_EQ("3", "us-ascii", text.getWordAt(0)->getCharset()); ferencd@0: VASSERT_EQ("4", "Br\xc3\xa4ndt", text.getWordAt(1)->getBuffer()); ferencd@0: VASSERT_EQ("5", "utf-8", text.getWordAt(1)->getCharset()); ferencd@0: ferencd@0: // Generate ferencd@0: VASSERT_EQ("6", "Achim =?utf-8?Q?Br=C3=A4ndt?=", text.generate()); ferencd@0: ferencd@0: // Parse ferencd@0: text.parse("=?us-ascii?Q?Achim_?= =?utf-8?Q?Br=C3=A4ndt?="); ferencd@0: ferencd@0: VASSERT_EQ("7", 2, text.getWordCount()); ferencd@0: VASSERT_EQ("8", "Achim ", text.getWordAt(0)->getBuffer()); ferencd@0: VASSERT_EQ("9", "us-ascii", text.getWordAt(0)->getCharset()); ferencd@0: VASSERT_EQ("10", "Br\xc3\xa4ndt", text.getWordAt(1)->getBuffer()); ferencd@0: VASSERT_EQ("11", "utf-8", text.getWordAt(1)->getCharset()); ferencd@0: } ferencd@0: ferencd@0: void testWhitespaceMBox() ferencd@0: { ferencd@0: // Space MUST be encoded inside a word ferencd@0: vmime::mailbox mbox(vmime::text("Achim Br\xc3\xa4ndt", vmime::charsets::UTF_8), "me@vmime.org"); ferencd@0: VASSERT_EQ("generate1", "=?us-ascii?Q?Achim_?= =?utf-8?Q?Br=C3=A4ndt?= ", mbox.generate()); ferencd@0: ferencd@0: vmime::text txt; ferencd@0: txt.appendWord(vmime::make_shared ("Achim ", "us-ascii")); ferencd@0: txt.appendWord(vmime::make_shared ("Br\xc3\xa4ndt", "utf-8")); ferencd@0: mbox = vmime::mailbox(txt, "me@vmime.org"); ferencd@0: VASSERT_EQ("generate2", "=?us-ascii?Q?Achim_?= =?utf-8?Q?Br=C3=A4ndt?= ", mbox.generate()); ferencd@0: ferencd@0: mbox.parse("=?us-ascii?Q?Achim?= =?utf-8?Q?Br=C3=A4ndt?= "); ferencd@0: VASSERT_EQ("parse.name.count", 2, mbox.getName().getWordCount()); ferencd@0: VASSERT_EQ("parse.name.word1.buffer", "Achim", mbox.getName().getWordAt(0)->getBuffer()); ferencd@0: VASSERT_EQ("parse.name.word1.charset", "us-ascii", mbox.getName().getWordAt(0)->getCharset()); ferencd@0: VASSERT_EQ("parse.name.word2.buffer", "Br\xc3\xa4ndt", mbox.getName().getWordAt(1)->getBuffer()); ferencd@0: VASSERT_EQ("parse.name.word2.charset", "utf-8", mbox.getName().getWordAt(1)->getCharset()); ferencd@0: ferencd@0: VASSERT_EQ("parse.email", "me@vmime.org", mbox.getEmail()); ferencd@0: } ferencd@0: ferencd@0: void testFoldingAscii() ferencd@0: { ferencd@0: // In this test, no encoding is needed, but line should be folded anyway ferencd@0: vmime::word w("01234567890123456789012345678901234567890123456789" ferencd@0: "01234567890123456789012345678901234567890123456789", vmime::charset("us-ascii")); ferencd@0: ferencd@0: VASSERT_EQ("fold.ascii", ferencd@0: "=?us-ascii?Q?01234567890123456789012345678901234?=\r\n" ferencd@0: " =?us-ascii?Q?5678901234567890123456789012345678?=\r\n" ferencd@0: " =?us-ascii?Q?9012345678901234567890123456789?=", w.generate(50)); ferencd@0: } ferencd@0: ferencd@0: void testForcedNonEncoding() ferencd@0: { ferencd@0: // Testing long unbreakable and unencodable header ferencd@0: vmime::relay r; ferencd@0: r.parse(" from User (Ee9GMqZQ8t7IQwftfAFHd2KyScCYRrFSJ50tKEoXv2bVCG4HcPU80GGWiFabAvG77FekpGgF1h@[127.0.0.1]) by servername.hostname.com\n\t" ferencd@0: "with esmtp id 1NGTS9-2C0sqG0; Fri, 4 Dec 2009 09:23:49 +0100"); ferencd@0: ferencd@0: 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)); ferencd@0: } ferencd@0: ferencd@0: void testBugFix20110511() ferencd@0: { ferencd@0: /* ferencd@0: ferencd@0: Using the latest version of vmime (0.9.1), encoding the following string: Jean ferencd@0: Gwenaël Dutourd will result in: ferencd@0: Jean =?utf-8?Q?Gwena=C3=ABl_?= Dutourd ferencd@0: However, decoding this will result in Jean Gwenaël Dutourd (notice two spaces ferencd@0: between the last 2 words). The encoder adds a _ after the second word, but ferencd@0: since the last word is not encoded, the space between them is not ignored, and ferencd@0: is decoded into an additional space. ferencd@0: ferencd@0: See: http://sourceforge.net/projects/vmime/forums/forum/237357/topic/4531365 ferencd@0: ferencd@0: */ ferencd@0: ferencd@0: const std::string DECODED_TEXT = "Jean Gwenaël Dutourd"; ferencd@0: const std::string ENCODED_TEXT = "Jean =?utf-8?Q?Gwena=C3=ABl?= Dutourd"; ferencd@0: ferencd@0: // Encode ferencd@0: VASSERT_EQ("encode", ENCODED_TEXT, ferencd@0: vmime::text::newFromString(DECODED_TEXT, vmime::charset("utf-8"))->generate()); ferencd@0: ferencd@0: // Decode ferencd@0: vmime::text t; ferencd@0: t.parse(ENCODED_TEXT); ferencd@0: ferencd@0: // -- words ferencd@0: std::ostringstream oss; oss << t; ferencd@0: VASSERT_EQ("decode1", ferencd@0: "[text: [[word: charset=us-ascii, buffer=Jean ]," ferencd@0: "[word: charset=utf-8, buffer=Gwenaël]," ferencd@0: "[word: charset=us-ascii, buffer= Dutourd]]]", oss.str()); ferencd@0: ferencd@0: // -- getWholeBuffer ferencd@0: VASSERT_EQ("decode2", DECODED_TEXT, t.getWholeBuffer()); ferencd@0: } ferencd@0: ferencd@0: void testInternationalizedEmail_specialChars() ferencd@0: { ferencd@0: vmime::generationContext ctx(vmime::generationContext::getDefaultContext()); ferencd@0: ctx.setInternationalizedEmailSupport(true); ferencd@0: ferencd@0: vmime::generationContext::switcher contextSwitcher(ctx); ferencd@0: ferencd@0: // Special sequence/chars should still be encoded ferencd@0: VASSERT_EQ("1", "=?us-ascii?Q?Test=3D=3Frfc2047_sequence?=", ferencd@0: vmime::word("Test=?rfc2047 sequence", vmime::charset("us-ascii")).generate()); ferencd@0: ferencd@0: VASSERT_EQ("2", "=?us-ascii?Q?Line_One=0ALine_Two?=", ferencd@0: vmime::word("Line One\nLine Two", vmime::charset("us-ascii")).generate()); ferencd@0: } ferencd@0: ferencd@0: void testInternationalizedEmail_UTF8() ferencd@0: { ferencd@0: vmime::generationContext ctx(vmime::generationContext::getDefaultContext()); ferencd@0: ctx.setInternationalizedEmailSupport(true); ferencd@0: ferencd@0: vmime::generationContext::switcher contextSwitcher(ctx); ferencd@0: ferencd@0: // Already UTF-8 encoded text should be left as is ferencd@0: VASSERT_EQ("1", "Achim Br\xc3\xa4ndt", ferencd@0: vmime::word("Achim Br\xc3\xa4ndt", vmime::charset("utf-8")).generate()); ferencd@0: } ferencd@0: ferencd@0: void testInternationalizedEmail_nonUTF8() ferencd@0: { ferencd@0: vmime::generationContext ctx(vmime::generationContext::getDefaultContext()); ferencd@0: ctx.setInternationalizedEmailSupport(true); ferencd@0: ferencd@0: vmime::generationContext::switcher contextSwitcher(ctx); ferencd@0: ferencd@0: // Non UTF-8 encoded text should first be converted to UTF-8 ferencd@0: VASSERT_EQ("1", "Achim Br\xc3\xa4ndt", ferencd@0: vmime::word("Achim Br\xe4ndt", vmime::charset("iso-8859-1")).generate()); ferencd@0: } ferencd@0: ferencd@0: void testInternationalizedEmail_folding() ferencd@0: { ferencd@0: vmime::generationContext ctx(vmime::generationContext::getDefaultContext()); ferencd@0: ctx.setInternationalizedEmailSupport(true); ferencd@0: ferencd@0: vmime::generationContext::switcher contextSwitcher(ctx); ferencd@0: ferencd@0: // RFC-2047 encoding must be performed, as line folding is needed ferencd@0: vmime::word w1("01234567890123456789\xc3\xa0x012345678901234567890123456789" ferencd@0: "01234567890123456789\xc3\xa0x012345678901234567890123456789", vmime::charset("utf-8")); ferencd@0: ferencd@0: VASSERT_EQ("1", ferencd@0: "=?utf-8?Q?01234567890123456789=C3=A0x01234567890?=\r\n" ferencd@0: " =?utf-8?Q?1234567890123456789012345678901234567?=\r\n" ferencd@0: " =?utf-8?Q?89=C3=A0x0123456789012345678901234567?=\r\n" ferencd@0: " =?utf-8?Q?89?=", w1.generate(50)); ferencd@0: ferencd@0: // RFC-2047 encoding will not be forced, as words can be wrapped in a new line ferencd@0: vmime::word w2("bla bla bla This is some '\xc3\xa0\xc3\xa7' UTF-8 encoded text", vmime::charset("utf-8")); ferencd@0: ferencd@0: VASSERT_EQ("2", ferencd@0: "bla bla bla This is\r\n" ferencd@0: " some '\xc3\xa0\xc3\xa7' UTF-8\r\n" ferencd@0: " encoded text", w2.generate(20)); ferencd@0: } ferencd@0: ferencd@0: VMIME_TEST_SUITE_END ferencd@0: