diff --git a/proguard.flags b/proguard.flags index be627dbbf..bbffc8a54 100644 --- a/proguard.flags +++ b/proguard.flags @@ -26,6 +26,10 @@ # Keep names that are used only by unit tests +-keep class ** { + *** *ForTest(...); +} + -keepclasseswithmembers class com.android.email.GroupMessagingListener { *** removeListener(com.android.email.MessagingListener); } @@ -168,4 +172,3 @@ -keep class org.apache.james.mime4j.message.Message { *; } - diff --git a/src/com/android/email/mail/Message.java b/src/com/android/email/mail/Message.java index 8906caf30..b23633786 100644 --- a/src/com/android/email/mail/Message.java +++ b/src/com/android/email/mail/Message.java @@ -117,7 +117,11 @@ public abstract class Message implements Part, Body { return getFlagSet().toArray(new Flag[] {}); } - public void setFlag(Flag flag, boolean set) throws MessagingException { + /** + * Set/clear a flag directly, without involving overrides of {@link #setFlag} in subclasses. + * Only used for testing. + */ + public final void setFlagDirectlyForTest(Flag flag, boolean set) throws MessagingException { if (set) { getFlagSet().add(flag); } else { @@ -125,6 +129,10 @@ public abstract class Message implements Part, Body { } } + public void setFlag(Flag flag, boolean set) throws MessagingException { + setFlagDirectlyForTest(flag, set); + } + /** * This method calls setFlag(Flag, boolean) * @param flags diff --git a/src/com/android/email/mail/store/ImapStore.java b/src/com/android/email/mail/store/ImapStore.java index 9ec912cfe..b4feb1658 100644 --- a/src/com/android/email/mail/store/ImapStore.java +++ b/src/com/android/email/mail/store/ImapStore.java @@ -1265,22 +1265,26 @@ public class ImapStore extends Store { uidList.append(messages[i].getUid()); } - StringBuilder flagList = new StringBuilder(); - for (int i = 0, count = flags.length; i < count; i++) { - Flag flag = flags[i]; - if (flag == Flag.SEEN) { - flagList.append(" \\Seen"); - } else if (flag == Flag.DELETED) { - flagList.append(" \\Deleted"); - } else if (flag == Flag.FLAGGED) { - flagList.append(" \\Flagged"); + String allFlags = ""; + if (flags.length > 0) { + StringBuilder flagList = new StringBuilder(); + for (int i = 0, count = flags.length; i < count; i++) { + Flag flag = flags[i]; + if (flag == Flag.SEEN) { + flagList.append(" \\Seen"); // TODO this can be a field of Flag... + } else if (flag == Flag.DELETED) { + flagList.append(" \\Deleted"); + } else if (flag == Flag.FLAGGED) { + flagList.append(" \\Flagged"); + } } + allFlags = flagList.substring(1); } try { mConnection.executeSimpleCommand(String.format("UID STORE %s %sFLAGS.SILENT (%s)", uidList, value ? "+" : "-", - flagList.substring(1))); // Remove the first space + allFlags)); } catch (IOException ioe) { throw ioExceptionHandler(mConnection, ioe); @@ -1513,6 +1517,7 @@ public class ImapStore extends Store { this.mSize = size; } + @Override public void parse(InputStream in) throws IOException, MessagingException { super.parse(in); } diff --git a/tests/src/com/android/email/mail/store/ImapStoreUnitTests.java b/tests/src/com/android/email/mail/store/ImapStoreUnitTests.java index 3223099b8..661fe5c1b 100644 --- a/tests/src/com/android/email/mail/store/ImapStoreUnitTests.java +++ b/tests/src/com/android/email/mail/store/ImapStoreUnitTests.java @@ -16,6 +16,7 @@ package com.android.email.mail.store; +import com.android.email.mail.Address; import com.android.email.mail.FetchProfile; import com.android.email.mail.Flag; import com.android.email.mail.Folder; @@ -25,8 +26,11 @@ import com.android.email.mail.Part; import com.android.email.mail.Transport; import com.android.email.mail.Folder.FolderType; import com.android.email.mail.Folder.OpenMode; +import com.android.email.mail.Message.RecipientType; import com.android.email.mail.internet.BinaryTempFileBody; import com.android.email.mail.internet.MimeUtility; +import com.android.email.mail.internet.TextBody; +import com.android.email.mail.store.ImapStore.ImapMessage; import com.android.email.mail.transport.DiscourseLogger; import com.android.email.mail.transport.MockTransport; @@ -48,6 +52,7 @@ import java.util.Locale; */ @SmallTest public class ImapStoreUnitTests extends AndroidTestCase { + private final static String[] NO_REPLY = new String[0]; /* These values are provided by setUp() */ private ImapStore mStore = null; @@ -555,4 +560,43 @@ public class ImapStoreUnitTests extends AndroidTestCase { // And the message is "SEEN". assertTrue(message1.isSet(Flag.SEEN)); } + + public void testAppendMessages() throws Exception { + MockTransport mock = openAndInjectMockTransport(); + setupOpenFolder(mock); + mFolder.open(OpenMode.READ_WRITE, null); + + ImapMessage message = (ImapMessage) mFolder.createMessage("1"); + message.setFrom(new Address("me@test.com")); + message.setRecipient(RecipientType.TO, new Address("you@test.com")); + message.setMessageId(""); + message.setFlagDirectlyForTest(Flag.SEEN, true); + message.setBody(new TextBody("Test Body")); + + // + go ahead + // * 12345 EXISTS + // OK [APPENDUID 627684530 17] (Success) + + mock.expect(getNextTag(false) + " APPEND \\\"INBOX\\\" \\(\\\\Seen\\) \\{166\\}", + new String[] {"+ go ahead"}); + + mock.expectLiterally("From: me@test.com", NO_REPLY); + mock.expectLiterally("To: you@test.com", NO_REPLY); + mock.expectLiterally("Message-ID: ", NO_REPLY); + mock.expectLiterally("Content-Type: text/plain;", NO_REPLY); + mock.expectLiterally(" charset=utf-8", NO_REPLY); + mock.expectLiterally("Content-Transfer-Encoding: base64", NO_REPLY); + mock.expectLiterally("", NO_REPLY); + mock.expectLiterally("VGVzdCBCb2R5", NO_REPLY); + mock.expectLiterally("", new String[] { + "* 7 EXISTS", + getNextTag(true) + " OK [APPENDUID 1234567 13] (Success)" + }); + + mFolder.appendMessages(new Message[] {message}); + mock.close(); + + assertEquals("13", message.getUid()); + assertEquals(7, mFolder.getMessageCount()); + } } diff --git a/tests/src/com/android/email/mail/transport/MockTransport.java b/tests/src/com/android/email/mail/transport/MockTransport.java index 3e72cee0a..b1cc3b462 100644 --- a/tests/src/com/android/email/mail/transport/MockTransport.java +++ b/tests/src/com/android/email/mail/transport/MockTransport.java @@ -26,6 +26,9 @@ import java.io.OutputStream; import java.net.URI; import java.util.ArrayList; import java.util.Arrays; +import java.util.regex.Pattern; + +import junit.framework.Assert; /** * This is a mock Transport that is used to test protocols that use MailTransport. @@ -115,7 +118,15 @@ public class MockTransport implements Transport { Transaction pair = new Transaction(pattern, responses); mPairs.add(pair); } - + + /** + * Same as {@link #expect(String, String[])}, but the first arg is taken literally, rather than + * as a regexp. + */ + public void expectLiterally(String literal, String[] responses) { + expect("^" + Pattern.quote(literal) + "$", responses); + } + /** * Tell the Mock Transport that we expect it to be closed. This will preserve * the remaining entries in the expect() stream and allow us to "ride over" the close (which @@ -192,7 +203,7 @@ public class MockTransport implements Transport { } public OutputStream getOutputStream() { - SmtpSenderUnitTests.assertTrue(mOpen); + Assert.assertTrue(mOpen); return new MockOutputStream(); } @@ -302,9 +313,11 @@ public class MockTransport implements Transport { Log.d(LOG_TAG, ">>> " + s); } SmtpSenderUnitTests.assertTrue(mOpen); - SmtpSenderUnitTests.assertTrue("Overflow writing to MockTransport", 0 != mPairs.size()); + SmtpSenderUnitTests.assertTrue("Overflow writing to MockTransport: Getting " + s, + 0 != mPairs.size()); Transaction pair = mPairs.remove(0); - SmtpSenderUnitTests.assertTrue("Unexpected string written to MockTransport", + SmtpSenderUnitTests.assertTrue("Unexpected string written to MockTransport: Actual=" + s + + " Expected=" + pair.mPattern, pair.mPattern != null && s.matches(pair.mPattern)); if (pair.mResponses != null) { sendResponse(pair.mResponses);