1d3eab5e6ffa39c931c2ca31e6670b7743723e034Marc Blank/*
2d3eab5e6ffa39c931c2ca31e6670b7743723e034Marc Blank * Copyright (C) 2010 The Android Open Source Project
3d3eab5e6ffa39c931c2ca31e6670b7743723e034Marc Blank *
4d3eab5e6ffa39c931c2ca31e6670b7743723e034Marc Blank * Licensed under the Apache License, Version 2.0 (the "License");
5d3eab5e6ffa39c931c2ca31e6670b7743723e034Marc Blank * you may not use this file except in compliance with the License.
6d3eab5e6ffa39c931c2ca31e6670b7743723e034Marc Blank * You may obtain a copy of the License at
7d3eab5e6ffa39c931c2ca31e6670b7743723e034Marc Blank *
8d3eab5e6ffa39c931c2ca31e6670b7743723e034Marc Blank *      http://www.apache.org/licenses/LICENSE-2.0
9d3eab5e6ffa39c931c2ca31e6670b7743723e034Marc Blank *
10d3eab5e6ffa39c931c2ca31e6670b7743723e034Marc Blank * Unless required by applicable law or agreed to in writing, software
11d3eab5e6ffa39c931c2ca31e6670b7743723e034Marc Blank * distributed under the License is distributed on an "AS IS" BASIS,
12d3eab5e6ffa39c931c2ca31e6670b7743723e034Marc Blank * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13d3eab5e6ffa39c931c2ca31e6670b7743723e034Marc Blank * See the License for the specific language governing permissions and
14d3eab5e6ffa39c931c2ca31e6670b7743723e034Marc Blank * limitations under the License.
15d3eab5e6ffa39c931c2ca31e6670b7743723e034Marc Blank */
16d3eab5e6ffa39c931c2ca31e6670b7743723e034Marc Blank
17d3eab5e6ffa39c931c2ca31e6670b7743723e034Marc Blankpackage com.android.exchange.adapter;
18d3eab5e6ffa39c931c2ca31e6670b7743723e034Marc Blank
19f80dd6855e64091ccac83f1bf37cd808ef2f3e71Marc Blankimport android.content.ContentResolver;
209f551ed0c2794a4ebb775df0dc5f714cf07f29b7Marc Blankimport android.content.res.AssetManager;
219f551ed0c2794a4ebb775df0dc5f714cf07f29b7Marc Blankimport android.database.Cursor;
22f80dd6855e64091ccac83f1bf37cd808ef2f3e71Marc Blankimport android.test.suitebuilder.annotation.MediumTest;
23f80dd6855e64091ccac83f1bf37cd808ef2f3e71Marc Blank
24f80dd6855e64091ccac83f1bf37cd808ef2f3e71Marc Blankimport com.android.emailcommon.provider.Account;
2592c9d37d883eaafdbe7d9428a5de017eee9f3d2bMarc Blankimport com.android.emailcommon.provider.EmailContent;
266c9b4545651f9be2edb16c0769a7886ec7f24c30Ben Komaloimport com.android.emailcommon.provider.Mailbox;
2792c9d37d883eaafdbe7d9428a5de017eee9f3d2bMarc Blankimport com.android.emailcommon.provider.EmailContent.MailboxColumns;
28f80dd6855e64091ccac83f1bf37cd808ef2f3e71Marc Blankimport com.android.emailcommon.service.SyncWindow;
299f551ed0c2794a4ebb775df0dc5f714cf07f29b7Marc Blankimport com.android.exchange.CommandStatusException;
30d3eab5e6ffa39c931c2ca31e6670b7743723e034Marc Blankimport com.android.exchange.EasSyncService;
31c8e4352ea6cfa67f15140512e84af8ccede222d2Marc Blankimport com.android.exchange.provider.EmailContentSetupUtils;
32d3eab5e6ffa39c931c2ca31e6670b7743723e034Marc Blank
339f551ed0c2794a4ebb775df0dc5f714cf07f29b7Marc Blankimport java.io.BufferedReader;
34d3eab5e6ffa39c931c2ca31e6670b7743723e034Marc Blankimport java.io.IOException;
359f551ed0c2794a4ebb775df0dc5f714cf07f29b7Marc Blankimport java.io.InputStream;
369f551ed0c2794a4ebb775df0dc5f714cf07f29b7Marc Blankimport java.io.InputStreamReader;
37d3eab5e6ffa39c931c2ca31e6670b7743723e034Marc Blankimport java.util.HashMap;
38d3eab5e6ffa39c931c2ca31e6670b7743723e034Marc Blank
39d3eab5e6ffa39c931c2ca31e6670b7743723e034Marc Blank/**
40d3eab5e6ffa39c931c2ca31e6670b7743723e034Marc Blank * You can run this entire test case with:
41c8e4352ea6cfa67f15140512e84af8ccede222d2Marc Blank *   runtest -c com.android.exchange.adapter.FolderSyncParserTests exchange
42d3eab5e6ffa39c931c2ca31e6670b7743723e034Marc Blank */
43604a1cf6f2401d78f57edcfb702d560d9c80dd14Marc Blank@MediumTest
44d3eab5e6ffa39c931c2ca31e6670b7743723e034Marc Blankpublic class FolderSyncParserTests extends SyncAdapterTestCase<EmailSyncAdapter> {
45d3eab5e6ffa39c931c2ca31e6670b7743723e034Marc Blank
46f80dd6855e64091ccac83f1bf37cd808ef2f3e71Marc Blank    // We increment this to generate unique server id's
47f80dd6855e64091ccac83f1bf37cd808ef2f3e71Marc Blank    private int mServerIdCount = 0;
48f80dd6855e64091ccac83f1bf37cd808ef2f3e71Marc Blank    private final long mCreationTime = System.currentTimeMillis();
499f551ed0c2794a4ebb775df0dc5f714cf07f29b7Marc Blank    private final String[] mMailboxQueryArgs = new String[2];
50f80dd6855e64091ccac83f1bf37cd808ef2f3e71Marc Blank
51d3eab5e6ffa39c931c2ca31e6670b7743723e034Marc Blank    public FolderSyncParserTests() {
52d3eab5e6ffa39c931c2ca31e6670b7743723e034Marc Blank        super();
53d3eab5e6ffa39c931c2ca31e6670b7743723e034Marc Blank    }
54d3eab5e6ffa39c931c2ca31e6670b7743723e034Marc Blank
55f80dd6855e64091ccac83f1bf37cd808ef2f3e71Marc Blank    private Mailbox setupBoxSync(int interval, int lookback, String serverId) {
56f80dd6855e64091ccac83f1bf37cd808ef2f3e71Marc Blank        // Don't save the box; just create it, and give it a server id
57f80dd6855e64091ccac83f1bf37cd808ef2f3e71Marc Blank        Mailbox box = EmailContentSetupUtils.setupMailbox("box1", mAccount.mId, false,
58f80dd6855e64091ccac83f1bf37cd808ef2f3e71Marc Blank                mProviderContext, Mailbox.TYPE_MAIL);
59f80dd6855e64091ccac83f1bf37cd808ef2f3e71Marc Blank        box.mSyncInterval = interval;
60f80dd6855e64091ccac83f1bf37cd808ef2f3e71Marc Blank        box.mSyncLookback = lookback;
61f80dd6855e64091ccac83f1bf37cd808ef2f3e71Marc Blank        if (serverId != null) {
62f80dd6855e64091ccac83f1bf37cd808ef2f3e71Marc Blank            box.mServerId = serverId;
63f80dd6855e64091ccac83f1bf37cd808ef2f3e71Marc Blank        } else {
64f80dd6855e64091ccac83f1bf37cd808ef2f3e71Marc Blank            box.mServerId = "serverId-" + mCreationTime + '-' + mServerIdCount++;
65f80dd6855e64091ccac83f1bf37cd808ef2f3e71Marc Blank        }
66f80dd6855e64091ccac83f1bf37cd808ef2f3e71Marc Blank        box.save(mProviderContext);
67f80dd6855e64091ccac83f1bf37cd808ef2f3e71Marc Blank        return box;
68f80dd6855e64091ccac83f1bf37cd808ef2f3e71Marc Blank    }
69f80dd6855e64091ccac83f1bf37cd808ef2f3e71Marc Blank
70f80dd6855e64091ccac83f1bf37cd808ef2f3e71Marc Blank    private boolean syncOptionsSame(Mailbox a, Mailbox b) {
71f80dd6855e64091ccac83f1bf37cd808ef2f3e71Marc Blank        if (a.mSyncInterval != b.mSyncInterval) return false;
72f80dd6855e64091ccac83f1bf37cd808ef2f3e71Marc Blank        if (a.mSyncLookback != b.mSyncLookback) return false;
73f80dd6855e64091ccac83f1bf37cd808ef2f3e71Marc Blank        return true;
74f80dd6855e64091ccac83f1bf37cd808ef2f3e71Marc Blank    }
75f80dd6855e64091ccac83f1bf37cd808ef2f3e71Marc Blank
76f80dd6855e64091ccac83f1bf37cd808ef2f3e71Marc Blank    public void testSaveAndRestoreMailboxSyncOptions() throws IOException {
77f80dd6855e64091ccac83f1bf37cd808ef2f3e71Marc Blank        EasSyncService service = getTestService();
78f80dd6855e64091ccac83f1bf37cd808ef2f3e71Marc Blank        EmailSyncAdapter adapter = new EmailSyncAdapter(service);
79f80dd6855e64091ccac83f1bf37cd808ef2f3e71Marc Blank        FolderSyncParser parser = new FolderSyncParser(getTestInputStream(), adapter);
80f80dd6855e64091ccac83f1bf37cd808ef2f3e71Marc Blank        mAccount.save(mProviderContext);
81f80dd6855e64091ccac83f1bf37cd808ef2f3e71Marc Blank
82f80dd6855e64091ccac83f1bf37cd808ef2f3e71Marc Blank        parser.mAccount = mAccount;
83f80dd6855e64091ccac83f1bf37cd808ef2f3e71Marc Blank        parser.mAccountId = mAccount.mId;
84f80dd6855e64091ccac83f1bf37cd808ef2f3e71Marc Blank        parser.mAccountIdAsString = Long.toString(mAccount.mId);
85f80dd6855e64091ccac83f1bf37cd808ef2f3e71Marc Blank        parser.mContext = mProviderContext;
86f80dd6855e64091ccac83f1bf37cd808ef2f3e71Marc Blank        parser.mContentResolver = mProviderContext.getContentResolver();
87f80dd6855e64091ccac83f1bf37cd808ef2f3e71Marc Blank
88f80dd6855e64091ccac83f1bf37cd808ef2f3e71Marc Blank        // Don't save the box; just create it, and give it a server id
8935b892c7570b06e72c97c0915d0e41abc83ed6b0Yu Ping Hu        Mailbox box1 = setupBoxSync(Account.CHECK_INTERVAL_NEVER, SyncWindow.SYNC_WINDOW_ACCOUNT,
90f80dd6855e64091ccac83f1bf37cd808ef2f3e71Marc Blank                null);
9135b892c7570b06e72c97c0915d0e41abc83ed6b0Yu Ping Hu        Mailbox box2 = setupBoxSync(Account.CHECK_INTERVAL_NEVER, SyncWindow.SYNC_WINDOW_ACCOUNT,
92f80dd6855e64091ccac83f1bf37cd808ef2f3e71Marc Blank                null);
93f80dd6855e64091ccac83f1bf37cd808ef2f3e71Marc Blank        Mailbox boxa = setupBoxSync(Account.CHECK_INTERVAL_NEVER, SyncWindow.SYNC_WINDOW_1_MONTH,
94f80dd6855e64091ccac83f1bf37cd808ef2f3e71Marc Blank                null);
95f80dd6855e64091ccac83f1bf37cd808ef2f3e71Marc Blank        Mailbox boxb = setupBoxSync(Account.CHECK_INTERVAL_NEVER, SyncWindow.SYNC_WINDOW_2_WEEKS,
96f80dd6855e64091ccac83f1bf37cd808ef2f3e71Marc Blank                null);
9735b892c7570b06e72c97c0915d0e41abc83ed6b0Yu Ping Hu        Mailbox boxc = setupBoxSync(Account.CHECK_INTERVAL_PUSH, SyncWindow.SYNC_WINDOW_ACCOUNT,
98f80dd6855e64091ccac83f1bf37cd808ef2f3e71Marc Blank                null);
9935b892c7570b06e72c97c0915d0e41abc83ed6b0Yu Ping Hu        Mailbox boxd = setupBoxSync(Account.CHECK_INTERVAL_PUSH, SyncWindow.SYNC_WINDOW_ACCOUNT,
100f80dd6855e64091ccac83f1bf37cd808ef2f3e71Marc Blank                null);
101f80dd6855e64091ccac83f1bf37cd808ef2f3e71Marc Blank        Mailbox boxe = setupBoxSync(Account.CHECK_INTERVAL_PUSH, SyncWindow.SYNC_WINDOW_1_DAY,
102f80dd6855e64091ccac83f1bf37cd808ef2f3e71Marc Blank                null);
103f80dd6855e64091ccac83f1bf37cd808ef2f3e71Marc Blank
104f80dd6855e64091ccac83f1bf37cd808ef2f3e71Marc Blank        // Save the options (for a, b, c, d, e);
105f80dd6855e64091ccac83f1bf37cd808ef2f3e71Marc Blank        parser.saveMailboxSyncOptions();
106f80dd6855e64091ccac83f1bf37cd808ef2f3e71Marc Blank        // There should be 5 entries in the map, and they should be the correct ones
107f80dd6855e64091ccac83f1bf37cd808ef2f3e71Marc Blank        assertNotNull(parser.mSyncOptionsMap.get(boxa.mServerId));
108f80dd6855e64091ccac83f1bf37cd808ef2f3e71Marc Blank        assertNotNull(parser.mSyncOptionsMap.get(boxb.mServerId));
109f80dd6855e64091ccac83f1bf37cd808ef2f3e71Marc Blank        assertNotNull(parser.mSyncOptionsMap.get(boxc.mServerId));
110f80dd6855e64091ccac83f1bf37cd808ef2f3e71Marc Blank        assertNotNull(parser.mSyncOptionsMap.get(boxd.mServerId));
111f80dd6855e64091ccac83f1bf37cd808ef2f3e71Marc Blank        assertNotNull(parser.mSyncOptionsMap.get(boxe.mServerId));
112f80dd6855e64091ccac83f1bf37cd808ef2f3e71Marc Blank
113f80dd6855e64091ccac83f1bf37cd808ef2f3e71Marc Blank        // Delete all the mailboxes in the account
114f80dd6855e64091ccac83f1bf37cd808ef2f3e71Marc Blank        ContentResolver cr = mProviderContext.getContentResolver();
115f80dd6855e64091ccac83f1bf37cd808ef2f3e71Marc Blank        cr.delete(Mailbox.CONTENT_URI, Mailbox.ACCOUNT_KEY + "=?",
116f80dd6855e64091ccac83f1bf37cd808ef2f3e71Marc Blank                new String[] {parser.mAccountIdAsString});
117f80dd6855e64091ccac83f1bf37cd808ef2f3e71Marc Blank
118f80dd6855e64091ccac83f1bf37cd808ef2f3e71Marc Blank        // Create new boxes, all with default values for interval & window
11935b892c7570b06e72c97c0915d0e41abc83ed6b0Yu Ping Hu        Mailbox box1x = setupBoxSync(Account.CHECK_INTERVAL_NEVER, SyncWindow.SYNC_WINDOW_ACCOUNT,
120f80dd6855e64091ccac83f1bf37cd808ef2f3e71Marc Blank                box1.mServerId);
12135b892c7570b06e72c97c0915d0e41abc83ed6b0Yu Ping Hu        Mailbox box2x = setupBoxSync(Account.CHECK_INTERVAL_NEVER, SyncWindow.SYNC_WINDOW_ACCOUNT,
122f80dd6855e64091ccac83f1bf37cd808ef2f3e71Marc Blank                box2.mServerId);
12335b892c7570b06e72c97c0915d0e41abc83ed6b0Yu Ping Hu        Mailbox boxax = setupBoxSync(Account.CHECK_INTERVAL_NEVER, SyncWindow.SYNC_WINDOW_ACCOUNT,
124f80dd6855e64091ccac83f1bf37cd808ef2f3e71Marc Blank                boxa.mServerId);
12535b892c7570b06e72c97c0915d0e41abc83ed6b0Yu Ping Hu        Mailbox boxbx = setupBoxSync(Account.CHECK_INTERVAL_NEVER, SyncWindow.SYNC_WINDOW_ACCOUNT,
126f80dd6855e64091ccac83f1bf37cd808ef2f3e71Marc Blank                boxb.mServerId);
12735b892c7570b06e72c97c0915d0e41abc83ed6b0Yu Ping Hu        Mailbox boxcx = setupBoxSync(Account.CHECK_INTERVAL_NEVER, SyncWindow.SYNC_WINDOW_ACCOUNT,
128f80dd6855e64091ccac83f1bf37cd808ef2f3e71Marc Blank                boxc.mServerId);
12935b892c7570b06e72c97c0915d0e41abc83ed6b0Yu Ping Hu        Mailbox boxdx = setupBoxSync(Account.CHECK_INTERVAL_NEVER, SyncWindow.SYNC_WINDOW_ACCOUNT,
130f80dd6855e64091ccac83f1bf37cd808ef2f3e71Marc Blank                boxd.mServerId);
13135b892c7570b06e72c97c0915d0e41abc83ed6b0Yu Ping Hu        Mailbox boxex = setupBoxSync(Account.CHECK_INTERVAL_NEVER, SyncWindow.SYNC_WINDOW_ACCOUNT,
132f80dd6855e64091ccac83f1bf37cd808ef2f3e71Marc Blank                boxe.mServerId);
133f80dd6855e64091ccac83f1bf37cd808ef2f3e71Marc Blank
134f80dd6855e64091ccac83f1bf37cd808ef2f3e71Marc Blank        // Restore the sync options
135f80dd6855e64091ccac83f1bf37cd808ef2f3e71Marc Blank        parser.restoreMailboxSyncOptions();
136f80dd6855e64091ccac83f1bf37cd808ef2f3e71Marc Blank        box1x = Mailbox.restoreMailboxWithId(mProviderContext, box1x.mId);
137f80dd6855e64091ccac83f1bf37cd808ef2f3e71Marc Blank        box2x = Mailbox.restoreMailboxWithId(mProviderContext, box2x.mId);
138f80dd6855e64091ccac83f1bf37cd808ef2f3e71Marc Blank        boxax = Mailbox.restoreMailboxWithId(mProviderContext, boxax.mId);
139f80dd6855e64091ccac83f1bf37cd808ef2f3e71Marc Blank        boxbx = Mailbox.restoreMailboxWithId(mProviderContext, boxbx.mId);
140f80dd6855e64091ccac83f1bf37cd808ef2f3e71Marc Blank        boxcx = Mailbox.restoreMailboxWithId(mProviderContext, boxcx.mId);
141f80dd6855e64091ccac83f1bf37cd808ef2f3e71Marc Blank        boxdx = Mailbox.restoreMailboxWithId(mProviderContext, boxdx.mId);
142f80dd6855e64091ccac83f1bf37cd808ef2f3e71Marc Blank        boxex = Mailbox.restoreMailboxWithId(mProviderContext, boxex.mId);
143f80dd6855e64091ccac83f1bf37cd808ef2f3e71Marc Blank
144f80dd6855e64091ccac83f1bf37cd808ef2f3e71Marc Blank        assertTrue(syncOptionsSame(box1, box1x));
145f80dd6855e64091ccac83f1bf37cd808ef2f3e71Marc Blank        assertTrue(syncOptionsSame(box2, box2x));
146f80dd6855e64091ccac83f1bf37cd808ef2f3e71Marc Blank        assertTrue(syncOptionsSame(boxa, boxax));
147f80dd6855e64091ccac83f1bf37cd808ef2f3e71Marc Blank        assertTrue(syncOptionsSame(boxb, boxbx));
148f80dd6855e64091ccac83f1bf37cd808ef2f3e71Marc Blank        assertTrue(syncOptionsSame(boxc, boxcx));
149f80dd6855e64091ccac83f1bf37cd808ef2f3e71Marc Blank        assertTrue(syncOptionsSame(boxd, boxdx));
150f80dd6855e64091ccac83f1bf37cd808ef2f3e71Marc Blank        assertTrue(syncOptionsSame(boxe, boxex));
151f80dd6855e64091ccac83f1bf37cd808ef2f3e71Marc Blank    }
1529f551ed0c2794a4ebb775df0dc5f714cf07f29b7Marc Blank
1539f551ed0c2794a4ebb775df0dc5f714cf07f29b7Marc Blank    private static class MockFolderSyncParser extends FolderSyncParser {
1549f551ed0c2794a4ebb775df0dc5f714cf07f29b7Marc Blank        private BufferedReader mReader;
1559f551ed0c2794a4ebb775df0dc5f714cf07f29b7Marc Blank        private int mDepth = 0;
1569f551ed0c2794a4ebb775df0dc5f714cf07f29b7Marc Blank        private String[] mStack = new String[32];
1579f551ed0c2794a4ebb775df0dc5f714cf07f29b7Marc Blank        private HashMap<String, Integer> mTagMap;
1589f551ed0c2794a4ebb775df0dc5f714cf07f29b7Marc Blank
1599f551ed0c2794a4ebb775df0dc5f714cf07f29b7Marc Blank
1609f551ed0c2794a4ebb775df0dc5f714cf07f29b7Marc Blank        public MockFolderSyncParser(String fileName, AbstractSyncAdapter adapter)
1619f551ed0c2794a4ebb775df0dc5f714cf07f29b7Marc Blank                throws IOException {
1629f551ed0c2794a4ebb775df0dc5f714cf07f29b7Marc Blank            super(null, adapter);
1639f551ed0c2794a4ebb775df0dc5f714cf07f29b7Marc Blank            AssetManager am = mContext.getAssets();
1649f551ed0c2794a4ebb775df0dc5f714cf07f29b7Marc Blank            InputStream is = am.open(fileName);
1659f551ed0c2794a4ebb775df0dc5f714cf07f29b7Marc Blank            if (is != null) {
1669f551ed0c2794a4ebb775df0dc5f714cf07f29b7Marc Blank                mReader = new BufferedReader(new InputStreamReader(is));
1679f551ed0c2794a4ebb775df0dc5f714cf07f29b7Marc Blank            }
1689f551ed0c2794a4ebb775df0dc5f714cf07f29b7Marc Blank        }
1699f551ed0c2794a4ebb775df0dc5f714cf07f29b7Marc Blank
1709f551ed0c2794a4ebb775df0dc5f714cf07f29b7Marc Blank        private void initTagMap() {
1719f551ed0c2794a4ebb775df0dc5f714cf07f29b7Marc Blank            mTagMap = new HashMap<String, Integer>();
1729f551ed0c2794a4ebb775df0dc5f714cf07f29b7Marc Blank            int pageNum = 0;
1739f551ed0c2794a4ebb775df0dc5f714cf07f29b7Marc Blank            for (String[] page: Tags.pages) {
1749f551ed0c2794a4ebb775df0dc5f714cf07f29b7Marc Blank                int tagNum = 5;
1759f551ed0c2794a4ebb775df0dc5f714cf07f29b7Marc Blank                for (String tag: page) {
1769f551ed0c2794a4ebb775df0dc5f714cf07f29b7Marc Blank                    if (mTagMap.containsKey(tag)) {
1779f551ed0c2794a4ebb775df0dc5f714cf07f29b7Marc Blank                        System.err.println("Duplicate tag: " + tag);
1789f551ed0c2794a4ebb775df0dc5f714cf07f29b7Marc Blank                    }
1799f551ed0c2794a4ebb775df0dc5f714cf07f29b7Marc Blank                    int val = (pageNum << Tags.PAGE_SHIFT) + tagNum;
1809f551ed0c2794a4ebb775df0dc5f714cf07f29b7Marc Blank                    mTagMap.put(tag, val);
1819f551ed0c2794a4ebb775df0dc5f714cf07f29b7Marc Blank                    tagNum++;
1829f551ed0c2794a4ebb775df0dc5f714cf07f29b7Marc Blank                }
1839f551ed0c2794a4ebb775df0dc5f714cf07f29b7Marc Blank                pageNum++;
1849f551ed0c2794a4ebb775df0dc5f714cf07f29b7Marc Blank            }
1859f551ed0c2794a4ebb775df0dc5f714cf07f29b7Marc Blank        }
1869f551ed0c2794a4ebb775df0dc5f714cf07f29b7Marc Blank
1879f551ed0c2794a4ebb775df0dc5f714cf07f29b7Marc Blank        private int lookupTag(String tagName) {
1889f551ed0c2794a4ebb775df0dc5f714cf07f29b7Marc Blank            if (mTagMap == null) {
1899f551ed0c2794a4ebb775df0dc5f714cf07f29b7Marc Blank                initTagMap();
1909f551ed0c2794a4ebb775df0dc5f714cf07f29b7Marc Blank            }
1919f551ed0c2794a4ebb775df0dc5f714cf07f29b7Marc Blank            int res = mTagMap.get(tagName);
1929f551ed0c2794a4ebb775df0dc5f714cf07f29b7Marc Blank            return res;
1939f551ed0c2794a4ebb775df0dc5f714cf07f29b7Marc Blank        }
1949f551ed0c2794a4ebb775df0dc5f714cf07f29b7Marc Blank
1959f551ed0c2794a4ebb775df0dc5f714cf07f29b7Marc Blank        private String getLine() throws IOException {
1969f551ed0c2794a4ebb775df0dc5f714cf07f29b7Marc Blank            while (true) {
1979f551ed0c2794a4ebb775df0dc5f714cf07f29b7Marc Blank                String line = mReader.readLine();
1989f551ed0c2794a4ebb775df0dc5f714cf07f29b7Marc Blank                if (line == null) {
1999f551ed0c2794a4ebb775df0dc5f714cf07f29b7Marc Blank                    return null;
2009f551ed0c2794a4ebb775df0dc5f714cf07f29b7Marc Blank                }
2019f551ed0c2794a4ebb775df0dc5f714cf07f29b7Marc Blank                int start = line.indexOf("| ");
2029f551ed0c2794a4ebb775df0dc5f714cf07f29b7Marc Blank                if (start > 2) {
2039f551ed0c2794a4ebb775df0dc5f714cf07f29b7Marc Blank                    return line.substring(start + 2);
2049f551ed0c2794a4ebb775df0dc5f714cf07f29b7Marc Blank                }
2059f551ed0c2794a4ebb775df0dc5f714cf07f29b7Marc Blank                // Keep looking for a suitable line
2069f551ed0c2794a4ebb775df0dc5f714cf07f29b7Marc Blank            }
2079f551ed0c2794a4ebb775df0dc5f714cf07f29b7Marc Blank        }
2089f551ed0c2794a4ebb775df0dc5f714cf07f29b7Marc Blank
2099f551ed0c2794a4ebb775df0dc5f714cf07f29b7Marc Blank        @Override
2109f551ed0c2794a4ebb775df0dc5f714cf07f29b7Marc Blank        public int getValueInt() throws IOException {
2119f551ed0c2794a4ebb775df0dc5f714cf07f29b7Marc Blank            return Integer.parseInt(getValue());
2129f551ed0c2794a4ebb775df0dc5f714cf07f29b7Marc Blank        }
2139f551ed0c2794a4ebb775df0dc5f714cf07f29b7Marc Blank
2149f551ed0c2794a4ebb775df0dc5f714cf07f29b7Marc Blank        @Override
2159f551ed0c2794a4ebb775df0dc5f714cf07f29b7Marc Blank        public String getValue() throws IOException {
2169f551ed0c2794a4ebb775df0dc5f714cf07f29b7Marc Blank            String line = getLine();
2179f551ed0c2794a4ebb775df0dc5f714cf07f29b7Marc Blank            if (line == null) throw new IOException();
2189f551ed0c2794a4ebb775df0dc5f714cf07f29b7Marc Blank            int start = line.indexOf(": ");
2199f551ed0c2794a4ebb775df0dc5f714cf07f29b7Marc Blank            if (start < 0) throw new IOException("Line has no value: " + line);
2209f551ed0c2794a4ebb775df0dc5f714cf07f29b7Marc Blank            try {
2219f551ed0c2794a4ebb775df0dc5f714cf07f29b7Marc Blank                return line.substring(start + 2).trim();
2229f551ed0c2794a4ebb775df0dc5f714cf07f29b7Marc Blank            } finally {
2239f551ed0c2794a4ebb775df0dc5f714cf07f29b7Marc Blank                if (nextTag(0) != END) {
2249f551ed0c2794a4ebb775df0dc5f714cf07f29b7Marc Blank                    throw new IOException("Value not followed by end tag: " + name);
2259f551ed0c2794a4ebb775df0dc5f714cf07f29b7Marc Blank                }
2269f551ed0c2794a4ebb775df0dc5f714cf07f29b7Marc Blank            }
2279f551ed0c2794a4ebb775df0dc5f714cf07f29b7Marc Blank        }
2289f551ed0c2794a4ebb775df0dc5f714cf07f29b7Marc Blank
2299f551ed0c2794a4ebb775df0dc5f714cf07f29b7Marc Blank        @Override
2309f551ed0c2794a4ebb775df0dc5f714cf07f29b7Marc Blank        public void skipTag() throws IOException {
2319f551ed0c2794a4ebb775df0dc5f714cf07f29b7Marc Blank            if (nextTag(0) == -1) {
2329f551ed0c2794a4ebb775df0dc5f714cf07f29b7Marc Blank                nextTag(0);
2339f551ed0c2794a4ebb775df0dc5f714cf07f29b7Marc Blank            }
2349f551ed0c2794a4ebb775df0dc5f714cf07f29b7Marc Blank        }
2359f551ed0c2794a4ebb775df0dc5f714cf07f29b7Marc Blank
2369f551ed0c2794a4ebb775df0dc5f714cf07f29b7Marc Blank        @Override
2379f551ed0c2794a4ebb775df0dc5f714cf07f29b7Marc Blank        public int nextTag(int endingTag) throws IOException {
2389f551ed0c2794a4ebb775df0dc5f714cf07f29b7Marc Blank            String line = getLine();
2399f551ed0c2794a4ebb775df0dc5f714cf07f29b7Marc Blank            if (line == null) {
2409f551ed0c2794a4ebb775df0dc5f714cf07f29b7Marc Blank                return DONE;
2419f551ed0c2794a4ebb775df0dc5f714cf07f29b7Marc Blank            }
2429f551ed0c2794a4ebb775df0dc5f714cf07f29b7Marc Blank            if (line.startsWith("</")) {
2439f551ed0c2794a4ebb775df0dc5f714cf07f29b7Marc Blank                int end = line.indexOf('>');
2449f551ed0c2794a4ebb775df0dc5f714cf07f29b7Marc Blank                String tagName = line.substring(2, end).trim();
2459f551ed0c2794a4ebb775df0dc5f714cf07f29b7Marc Blank                if (!tagName.equals(mStack[--mDepth])) {
2469f551ed0c2794a4ebb775df0dc5f714cf07f29b7Marc Blank                    throw new IOException("Tag end doesn't match tag");
2479f551ed0c2794a4ebb775df0dc5f714cf07f29b7Marc Blank                }
2489f551ed0c2794a4ebb775df0dc5f714cf07f29b7Marc Blank                mStack[mDepth] = null;
2499f551ed0c2794a4ebb775df0dc5f714cf07f29b7Marc Blank                return END;
2509f551ed0c2794a4ebb775df0dc5f714cf07f29b7Marc Blank            } else if (line.startsWith("<")) {
2519f551ed0c2794a4ebb775df0dc5f714cf07f29b7Marc Blank                int end = line.indexOf('>');
2529f551ed0c2794a4ebb775df0dc5f714cf07f29b7Marc Blank                String tagName = line.substring(1, end).trim();
2539f551ed0c2794a4ebb775df0dc5f714cf07f29b7Marc Blank                mStack[mDepth++] = tagName;
2549f551ed0c2794a4ebb775df0dc5f714cf07f29b7Marc Blank                tag = lookupTag(tagName);
2559f551ed0c2794a4ebb775df0dc5f714cf07f29b7Marc Blank                return tag;
2569f551ed0c2794a4ebb775df0dc5f714cf07f29b7Marc Blank            } else {
2579f551ed0c2794a4ebb775df0dc5f714cf07f29b7Marc Blank                return -1;
2589f551ed0c2794a4ebb775df0dc5f714cf07f29b7Marc Blank            }
2599f551ed0c2794a4ebb775df0dc5f714cf07f29b7Marc Blank        }
2609f551ed0c2794a4ebb775df0dc5f714cf07f29b7Marc Blank    }
2619f551ed0c2794a4ebb775df0dc5f714cf07f29b7Marc Blank
2629f551ed0c2794a4ebb775df0dc5f714cf07f29b7Marc Blank    private Mailbox getMailboxWithName(String folderName) {
2639f551ed0c2794a4ebb775df0dc5f714cf07f29b7Marc Blank        mMailboxQueryArgs[1] = folderName;
2649f551ed0c2794a4ebb775df0dc5f714cf07f29b7Marc Blank        Cursor c = mResolver.query(Mailbox.CONTENT_URI, Mailbox.CONTENT_PROJECTION,
2659f551ed0c2794a4ebb775df0dc5f714cf07f29b7Marc Blank                Mailbox.ACCOUNT_KEY + "=? AND " + Mailbox.DISPLAY_NAME + "=?", mMailboxQueryArgs,
2669f551ed0c2794a4ebb775df0dc5f714cf07f29b7Marc Blank                null);
2679f551ed0c2794a4ebb775df0dc5f714cf07f29b7Marc Blank        try {
2689f551ed0c2794a4ebb775df0dc5f714cf07f29b7Marc Blank            assertTrue(c.getCount() == 1);
2699f551ed0c2794a4ebb775df0dc5f714cf07f29b7Marc Blank            c.moveToFirst();
2709f551ed0c2794a4ebb775df0dc5f714cf07f29b7Marc Blank            Mailbox m = new Mailbox();
2719f551ed0c2794a4ebb775df0dc5f714cf07f29b7Marc Blank            m.restore(c);
2729f551ed0c2794a4ebb775df0dc5f714cf07f29b7Marc Blank            return m;
2739f551ed0c2794a4ebb775df0dc5f714cf07f29b7Marc Blank        } finally {
2749f551ed0c2794a4ebb775df0dc5f714cf07f29b7Marc Blank            c.close();
2759f551ed0c2794a4ebb775df0dc5f714cf07f29b7Marc Blank        }
2769f551ed0c2794a4ebb775df0dc5f714cf07f29b7Marc Blank    }
2779f551ed0c2794a4ebb775df0dc5f714cf07f29b7Marc Blank
2789f551ed0c2794a4ebb775df0dc5f714cf07f29b7Marc Blank    private boolean isTopLevel(String folderName) {
2799f551ed0c2794a4ebb775df0dc5f714cf07f29b7Marc Blank        Mailbox m = getMailboxWithName(folderName);
2809f551ed0c2794a4ebb775df0dc5f714cf07f29b7Marc Blank        assertNotNull(m);
2819f551ed0c2794a4ebb775df0dc5f714cf07f29b7Marc Blank        return m.mParentKey == Mailbox.NO_MAILBOX;
2829f551ed0c2794a4ebb775df0dc5f714cf07f29b7Marc Blank    }
2839f551ed0c2794a4ebb775df0dc5f714cf07f29b7Marc Blank
2849f551ed0c2794a4ebb775df0dc5f714cf07f29b7Marc Blank    private boolean isSubfolder(String parentName, String childName) {
2859f551ed0c2794a4ebb775df0dc5f714cf07f29b7Marc Blank        Mailbox parent = getMailboxWithName(parentName);
2869f551ed0c2794a4ebb775df0dc5f714cf07f29b7Marc Blank        Mailbox child = getMailboxWithName(childName);
2879f551ed0c2794a4ebb775df0dc5f714cf07f29b7Marc Blank        assertNotNull(parent);
2889f551ed0c2794a4ebb775df0dc5f714cf07f29b7Marc Blank        assertNotNull(child);
2899f551ed0c2794a4ebb775df0dc5f714cf07f29b7Marc Blank        assertTrue((parent.mFlags & Mailbox.FLAG_HAS_CHILDREN) != 0);
2909f551ed0c2794a4ebb775df0dc5f714cf07f29b7Marc Blank        return child.mParentKey == parent.mId;
2919f551ed0c2794a4ebb775df0dc5f714cf07f29b7Marc Blank    }
2929f551ed0c2794a4ebb775df0dc5f714cf07f29b7Marc Blank
2939f551ed0c2794a4ebb775df0dc5f714cf07f29b7Marc Blank    /**
2949f551ed0c2794a4ebb775df0dc5f714cf07f29b7Marc Blank     * Parse a set of EAS FolderSync commands and create the Mailbox tree accordingly
2959f551ed0c2794a4ebb775df0dc5f714cf07f29b7Marc Blank     *
2969f551ed0c2794a4ebb775df0dc5f714cf07f29b7Marc Blank     * @param fileName the name of the file containing emaillog data for folder sync
2979f551ed0c2794a4ebb775df0dc5f714cf07f29b7Marc Blank     * @throws IOException
2989f551ed0c2794a4ebb775df0dc5f714cf07f29b7Marc Blank     * @throws CommandStatusException
2999f551ed0c2794a4ebb775df0dc5f714cf07f29b7Marc Blank     */
3009f551ed0c2794a4ebb775df0dc5f714cf07f29b7Marc Blank    private void testComplexFolderListParse(String fileName) throws IOException,
30192c9d37d883eaafdbe7d9428a5de017eee9f3d2bMarc Blank            CommandStatusException {
3029f551ed0c2794a4ebb775df0dc5f714cf07f29b7Marc Blank        EasSyncService service = getTestService();
3039f551ed0c2794a4ebb775df0dc5f714cf07f29b7Marc Blank        EmailSyncAdapter adapter = new EmailSyncAdapter(service);
3049f551ed0c2794a4ebb775df0dc5f714cf07f29b7Marc Blank        FolderSyncParser parser = new MockFolderSyncParser(fileName, adapter);
3059f551ed0c2794a4ebb775df0dc5f714cf07f29b7Marc Blank        mAccount.save(mProviderContext);
3069f551ed0c2794a4ebb775df0dc5f714cf07f29b7Marc Blank        mMailboxQueryArgs[0] = Long.toString(mAccount.mId);
3079f551ed0c2794a4ebb775df0dc5f714cf07f29b7Marc Blank        parser.mAccount = mAccount;
3089f551ed0c2794a4ebb775df0dc5f714cf07f29b7Marc Blank        parser.mAccountId = mAccount.mId;
3099f551ed0c2794a4ebb775df0dc5f714cf07f29b7Marc Blank        parser.mAccountIdAsString = Long.toString(mAccount.mId);
3109f551ed0c2794a4ebb775df0dc5f714cf07f29b7Marc Blank        parser.mContext = mProviderContext;
3119f551ed0c2794a4ebb775df0dc5f714cf07f29b7Marc Blank        parser.mContentResolver = mResolver;
3129f551ed0c2794a4ebb775df0dc5f714cf07f29b7Marc Blank
3139f551ed0c2794a4ebb775df0dc5f714cf07f29b7Marc Blank        parser.parse();
3149f551ed0c2794a4ebb775df0dc5f714cf07f29b7Marc Blank
3159f551ed0c2794a4ebb775df0dc5f714cf07f29b7Marc Blank        assertTrue(isTopLevel("Inbox"));
3169f551ed0c2794a4ebb775df0dc5f714cf07f29b7Marc Blank        assertTrue(isSubfolder("Inbox", "Gecko"));
3179f551ed0c2794a4ebb775df0dc5f714cf07f29b7Marc Blank        assertTrue(isSubfolder("Inbox", "Wombat"));
3189f551ed0c2794a4ebb775df0dc5f714cf07f29b7Marc Blank        assertTrue(isSubfolder("Inbox", "Laslo"));
3199f551ed0c2794a4ebb775df0dc5f714cf07f29b7Marc Blank        assertTrue(isSubfolder("Inbox", "Tomorrow"));
3209f551ed0c2794a4ebb775df0dc5f714cf07f29b7Marc Blank        assertTrue(isSubfolder("Inbox", "Vader"));
3219f551ed0c2794a4ebb775df0dc5f714cf07f29b7Marc Blank        assertTrue(isSubfolder("Inbox", "Personal"));
3229f551ed0c2794a4ebb775df0dc5f714cf07f29b7Marc Blank        assertTrue(isSubfolder("Laslo", "Lego"));
3239f551ed0c2794a4ebb775df0dc5f714cf07f29b7Marc Blank        assertTrue(isSubfolder("Tomorrow", "HomeRun"));
3249f551ed0c2794a4ebb775df0dc5f714cf07f29b7Marc Blank        assertTrue(isSubfolder("Tomorrow", "Services"));
3259f551ed0c2794a4ebb775df0dc5f714cf07f29b7Marc Blank        assertTrue(isSubfolder("HomeRun", "Review"));
3269f551ed0c2794a4ebb775df0dc5f714cf07f29b7Marc Blank        assertTrue(isSubfolder("Vader", "Max"));
3279f551ed0c2794a4ebb775df0dc5f714cf07f29b7Marc Blank        assertTrue(isSubfolder("Vader", "Parser"));
3289f551ed0c2794a4ebb775df0dc5f714cf07f29b7Marc Blank        assertTrue(isSubfolder("Vader", "Scott"));
3299f551ed0c2794a4ebb775df0dc5f714cf07f29b7Marc Blank        assertTrue(isSubfolder("Vader", "Surfing"));
3309f551ed0c2794a4ebb775df0dc5f714cf07f29b7Marc Blank        assertTrue(isSubfolder("Max", "Thomas"));
3319f551ed0c2794a4ebb775df0dc5f714cf07f29b7Marc Blank        assertTrue(isSubfolder("Personal", "Famine"));
3329f551ed0c2794a4ebb775df0dc5f714cf07f29b7Marc Blank        assertTrue(isSubfolder("Personal", "Bar"));
3339f551ed0c2794a4ebb775df0dc5f714cf07f29b7Marc Blank        assertTrue(isSubfolder("Personal", "Bill"));
3349f551ed0c2794a4ebb775df0dc5f714cf07f29b7Marc Blank        assertTrue(isSubfolder("Personal", "Boss"));
3359f551ed0c2794a4ebb775df0dc5f714cf07f29b7Marc Blank        assertTrue(isSubfolder("Personal", "Houston"));
3369f551ed0c2794a4ebb775df0dc5f714cf07f29b7Marc Blank        assertTrue(isSubfolder("Personal", "Mistake"));
3379f551ed0c2794a4ebb775df0dc5f714cf07f29b7Marc Blank        assertTrue(isSubfolder("Personal", "Online"));
3389f551ed0c2794a4ebb775df0dc5f714cf07f29b7Marc Blank        assertTrue(isSubfolder("Personal", "Sports"));
3399f551ed0c2794a4ebb775df0dc5f714cf07f29b7Marc Blank        assertTrue(isSubfolder("Famine", "Buffalo"));
3409f551ed0c2794a4ebb775df0dc5f714cf07f29b7Marc Blank        assertTrue(isSubfolder("Famine", "CornedBeef"));
3419f551ed0c2794a4ebb775df0dc5f714cf07f29b7Marc Blank        assertTrue(isSubfolder("Houston", "Rebar"));
3429f551ed0c2794a4ebb775df0dc5f714cf07f29b7Marc Blank        assertTrue(isSubfolder("Mistake", "Intro"));
3439f551ed0c2794a4ebb775df0dc5f714cf07f29b7Marc Blank    }
3449f551ed0c2794a4ebb775df0dc5f714cf07f29b7Marc Blank
3459f551ed0c2794a4ebb775df0dc5f714cf07f29b7Marc Blank    // FolderSyncParserTest.txt is based on customer data (all names changed) that failed to
3469f551ed0c2794a4ebb775df0dc5f714cf07f29b7Marc Blank    // properly create the Mailbox list
3479f551ed0c2794a4ebb775df0dc5f714cf07f29b7Marc Blank    public void testComplexFolderListParse1() throws CommandStatusException, IOException {
3489f551ed0c2794a4ebb775df0dc5f714cf07f29b7Marc Blank        testComplexFolderListParse("FolderSyncParserTest.txt");
3499f551ed0c2794a4ebb775df0dc5f714cf07f29b7Marc Blank    }
3509f551ed0c2794a4ebb775df0dc5f714cf07f29b7Marc Blank
3519f551ed0c2794a4ebb775df0dc5f714cf07f29b7Marc Blank    // As above, with the order changed (putting children before parents; a more difficult case
3529f551ed0c2794a4ebb775df0dc5f714cf07f29b7Marc Blank    public void testComplexFolderListParse2() throws CommandStatusException, IOException {
3539f551ed0c2794a4ebb775df0dc5f714cf07f29b7Marc Blank        testComplexFolderListParse("FolderSyncParserTest2.txt");
3549f551ed0c2794a4ebb775df0dc5f714cf07f29b7Marc Blank    }
35592c9d37d883eaafdbe7d9428a5de017eee9f3d2bMarc Blank
35692c9d37d883eaafdbe7d9428a5de017eee9f3d2bMarc Blank    // Much larger test (from user with issues related to Type 1 folders)
35792c9d37d883eaafdbe7d9428a5de017eee9f3d2bMarc Blank    public void testComplexFolderListParse3() throws CommandStatusException, IOException {
35892c9d37d883eaafdbe7d9428a5de017eee9f3d2bMarc Blank        EasSyncService service = getTestService();
35992c9d37d883eaafdbe7d9428a5de017eee9f3d2bMarc Blank        EmailSyncAdapter adapter = new EmailSyncAdapter(service);
36092c9d37d883eaafdbe7d9428a5de017eee9f3d2bMarc Blank        FolderSyncParser parser = new MockFolderSyncParser("FolderSyncParserTest3.txt", adapter);
36192c9d37d883eaafdbe7d9428a5de017eee9f3d2bMarc Blank        mAccount.save(mProviderContext);
36292c9d37d883eaafdbe7d9428a5de017eee9f3d2bMarc Blank        mMailboxQueryArgs[0] = Long.toString(mAccount.mId);
36392c9d37d883eaafdbe7d9428a5de017eee9f3d2bMarc Blank        parser.mAccount = mAccount;
36492c9d37d883eaafdbe7d9428a5de017eee9f3d2bMarc Blank        parser.mAccountId = mAccount.mId;
36592c9d37d883eaafdbe7d9428a5de017eee9f3d2bMarc Blank        parser.mAccountIdAsString = Long.toString(mAccount.mId);
36692c9d37d883eaafdbe7d9428a5de017eee9f3d2bMarc Blank        parser.mContext = mProviderContext;
36792c9d37d883eaafdbe7d9428a5de017eee9f3d2bMarc Blank        parser.mContentResolver = mResolver;
36892c9d37d883eaafdbe7d9428a5de017eee9f3d2bMarc Blank        parser.parse();
36992c9d37d883eaafdbe7d9428a5de017eee9f3d2bMarc Blank
37092c9d37d883eaafdbe7d9428a5de017eee9f3d2bMarc Blank        int cnt = EmailContent.count(mProviderContext, Mailbox.CONTENT_URI,
37192c9d37d883eaafdbe7d9428a5de017eee9f3d2bMarc Blank                MailboxColumns.ACCOUNT_KEY + "=" + mAccount.mId, null);
37292c9d37d883eaafdbe7d9428a5de017eee9f3d2bMarc Blank        // 270 in the file less 4 "conflicts" folders
37392c9d37d883eaafdbe7d9428a5de017eee9f3d2bMarc Blank        assertEquals(266, cnt);
37492c9d37d883eaafdbe7d9428a5de017eee9f3d2bMarc Blank    }
375d3eab5e6ffa39c931c2ca31e6670b7743723e034Marc Blank}
376