From 057309c14789daabdbe8a3f0a78c1056e979f67b Mon Sep 17 00:00:00 2001 From: Vincent Breitmoser Date: Mon, 8 Feb 2016 22:37:11 +0100 Subject: [PATCH] migration: test and nail down MimeStructureState behavior some more --- .../k9/mailstore/StoreSchemaDefinition.java | 11 +- .../MigrationMimeStructureStateTest.java | 150 ++++++++++++++++++ 2 files changed, 158 insertions(+), 3 deletions(-) create mode 100644 k9mail/src/test/java/com/fsck/k9/mailstore/MigrationMimeStructureStateTest.java diff --git a/k9mail/src/main/java/com/fsck/k9/mailstore/StoreSchemaDefinition.java b/k9mail/src/main/java/com/fsck/k9/mailstore/StoreSchemaDefinition.java index ea7ed6209..16a3cafa2 100644 --- a/k9mail/src/main/java/com/fsck/k9/mailstore/StoreSchemaDefinition.java +++ b/k9mail/src/main/java/com/fsck/k9/mailstore/StoreSchemaDefinition.java @@ -17,6 +17,7 @@ import android.database.sqlite.SQLiteException; import android.net.Uri; import android.support.annotation.NonNull; import android.support.annotation.Nullable; +import android.support.annotation.VisibleForTesting; import android.text.TextUtils; import android.util.Log; @@ -155,7 +156,8 @@ class StoreSchemaDefinition implements LockableDatabase.SchemaDefinition { * strictly linear, we do not require a more complex stack-based data structure * here. */ - private static class MimeStructureState { + @VisibleForTesting + static class MimeStructureState { private final Long rootPartId; private final Long prevParentId; private final long parentId; @@ -177,7 +179,7 @@ class StoreSchemaDefinition implements LockableDatabase.SchemaDefinition { return new MimeStructureState(null, null, -1, 0); } - private MimeStructureState nextChild(long newPartId) { + public MimeStructureState nextChild(long newPartId) { if (!isValuesApplied || isStateAdvanced) { throw new IllegalStateException("next* methods must only be called once"); } @@ -189,7 +191,7 @@ class StoreSchemaDefinition implements LockableDatabase.SchemaDefinition { return new MimeStructureState(rootPartId, prevParentId, parentId, nextOrder+1); } - private MimeStructureState nextMultipartChild(long newPartId) { + public MimeStructureState nextMultipartChild(long newPartId) { if (!isValuesApplied || isStateAdvanced) { throw new IllegalStateException("next* methods must only be called once"); } @@ -205,6 +207,9 @@ class StoreSchemaDefinition implements LockableDatabase.SchemaDefinition { if (isValuesApplied || isStateAdvanced) { throw new IllegalStateException("applyValues must be called exactly once, after a call to next*"); } + if (rootPartId != null && parentId == -1L) { + throw new IllegalStateException("applyValues must not be called after a root nextChild call"); + } isValuesApplied = true; if (rootPartId != null) { diff --git a/k9mail/src/test/java/com/fsck/k9/mailstore/MigrationMimeStructureStateTest.java b/k9mail/src/test/java/com/fsck/k9/mailstore/MigrationMimeStructureStateTest.java new file mode 100644 index 000000000..aa2ac11c3 --- /dev/null +++ b/k9mail/src/test/java/com/fsck/k9/mailstore/MigrationMimeStructureStateTest.java @@ -0,0 +1,150 @@ +package com.fsck.k9.mailstore; + + +import android.content.ContentValues; + +import com.fsck.k9.mailstore.StoreSchemaDefinition.MimeStructureState; +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.robolectric.RobolectricTestRunner; +import org.robolectric.annotation.Config; + + +@RunWith(RobolectricTestRunner.class) // required for ContentValues +@Config(manifest = "src/main/AndroidManifest.xml", sdk = 21) +public class MigrationMimeStructureStateTest { + + @Test(expected = IllegalStateException.class) + public void init_popParent_shouldCrash() throws Exception { + MimeStructureState state = MimeStructureState.getNewRootState(); + + state.popParent(); + } + + @Test(expected = IllegalStateException.class) + public void init_apply_apply_shouldCrash() throws Exception { + MimeStructureState state = MimeStructureState.getNewRootState(); + + ContentValues cv = new ContentValues(); + state.applyValues(cv); + + state.applyValues(cv); + } + + @Test(expected = IllegalStateException.class) + public void init_nextchild_shouldCrash() throws Exception { + MimeStructureState state = MimeStructureState.getNewRootState(); + + state.nextChild(1); + } + + @Test(expected = IllegalStateException.class) + public void init_nextmulti_shouldCrash() throws Exception { + MimeStructureState state = MimeStructureState.getNewRootState(); + + state.nextMultipartChild(1); + } + + @Test(expected = IllegalStateException.class) + public void init_apply_nextmulti_nextchild_shouldCrash() throws Exception { + MimeStructureState state = MimeStructureState.getNewRootState(); + + ContentValues cv = new ContentValues(); + state.applyValues(cv); + state.nextMultipartChild(1); + + state.nextChild(1); + } + + @Test(expected = IllegalStateException.class) + public void init_apply_nextchild_nextmulti_shouldCrash() throws Exception { + MimeStructureState state = MimeStructureState.getNewRootState(); + + ContentValues cv = new ContentValues(); + state.applyValues(cv); + state.nextChild(1); + + state.nextMultipartChild(1); + } + + @Test + public void init_apply_shouldYieldStartValues() throws Exception { + MimeStructureState state = MimeStructureState.getNewRootState(); + + ContentValues cv = new ContentValues(); + state.applyValues(cv); + + Assert.assertEquals(-1L, cv.get("parent")); + Assert.assertEquals(0, cv.get("seq")); + Assert.assertEquals(2, cv.size()); + } + + @Test(expected = IllegalStateException.class) + public void init_apply_nextchild_apply_shouldCrash() throws Exception { + MimeStructureState state = MimeStructureState.getNewRootState(); + + ContentValues cv = new ContentValues(); + state.applyValues(cv); + state = state.nextChild(123); + cv.clear(); + + state.applyValues(cv); + } + + @Test + public void init_apply_nextmulti_apply_shouldYieldMultipartChildValues() throws Exception { + MimeStructureState state = MimeStructureState.getNewRootState(); + + ContentValues cv = new ContentValues(); + state.applyValues(cv); + state = state.nextMultipartChild(123); + cv.clear(); + state.applyValues(cv); + + Assert.assertEquals(123L, cv.get("root")); + Assert.assertEquals(123L, cv.get("parent")); + Assert.assertEquals(1, cv.get("seq")); + Assert.assertEquals(3, cv.size()); + } + + @Test + public void init_apply_nextmulti_apply_nextmulti_apply_shouldYieldSecondMultipartChildValues() throws Exception { + MimeStructureState state = MimeStructureState.getNewRootState(); + + ContentValues cv = new ContentValues(); + state.applyValues(cv); + state = state.nextMultipartChild(123); + cv.clear(); + state.applyValues(cv); + state = state.nextMultipartChild(456); + cv.clear(); + state.applyValues(cv); + + Assert.assertEquals(123L, cv.get("root")); + Assert.assertEquals(456L, cv.get("parent")); + Assert.assertEquals(2, cv.get("seq")); + Assert.assertEquals(3, cv.size()); + } + + @Test + public void init_apply_nextmulti_apply_pop_apply_shouldYieldFirstParentIdValues() throws Exception { + MimeStructureState state = MimeStructureState.getNewRootState(); + + ContentValues cv = new ContentValues(); + state.applyValues(cv); + state = state.nextMultipartChild(123); + cv.clear(); + state.applyValues(cv); + state = state.nextMultipartChild(456); + state = state.popParent(); + cv.clear(); + state.applyValues(cv); + + Assert.assertEquals(123L, cv.get("root")); + Assert.assertEquals(123L, cv.get("parent")); + Assert.assertEquals(2, cv.get("seq")); + Assert.assertEquals(3, cv.size()); + } + +}