diff options
Diffstat (limited to 'storage/database')
4 files changed, 338 insertions, 4 deletions
diff --git a/storage/database/build.gradle b/storage/database/build.gradle index 63f9eeaec..a78afbf79 100644 --- a/storage/database/build.gradle +++ b/storage/database/build.gradle @@ -28,6 +28,9 @@ dependencies { implementation "commons-io:commons-io:$commonsioVersion" implementation "org.greenrobot:eventbus:$eventbusVersion" implementation "com.google.guava:guava:31.0.1-android" + implementation "org.apache.commons:commons-lang3:$commonslangVersion" testImplementation "junit:junit:$junitVersion" + testImplementation "androidx.test:core:$testCoreVersion" + testImplementation "org.robolectric:robolectric:$robolectricVersion" } diff --git a/storage/database/src/main/java/de/danoeh/antennapod/storage/database/FeedItemDuplicateGuesser.java b/storage/database/src/main/java/de/danoeh/antennapod/storage/database/FeedItemDuplicateGuesser.java index bbaedb519..19a2bd5f1 100644 --- a/storage/database/src/main/java/de/danoeh/antennapod/storage/database/FeedItemDuplicateGuesser.java +++ b/storage/database/src/main/java/de/danoeh/antennapod/storage/database/FeedItemDuplicateGuesser.java @@ -1,11 +1,11 @@ package de.danoeh.antennapod.storage.database; -import android.text.TextUtils; import de.danoeh.antennapod.model.feed.FeedItem; import de.danoeh.antennapod.model.feed.FeedMedia; import java.text.DateFormat; import java.util.Locale; +import org.apache.commons.lang3.StringUtils; /** * Publishers sometimes mess up their feed by adding episodes twice or by changing the ID of existing episodes. @@ -32,7 +32,7 @@ public class FeedItemDuplicateGuesser { } public static boolean sameAndNotEmpty(String string1, String string2) { - if (TextUtils.isEmpty(string1) || TextUtils.isEmpty(string2)) { + if (StringUtils.isEmpty(string1) || StringUtils.isEmpty(string2)) { return false; } return string1.equals(string2); @@ -45,7 +45,7 @@ public class FeedItemDuplicateGuesser { DateFormat dateFormat = DateFormat.getDateInstance(DateFormat.SHORT, Locale.US); // MM/DD/YY String dateOriginal = dateFormat.format(item2.getPubDate()); String dateNew = dateFormat.format(item1.getPubDate()); - return TextUtils.equals(dateOriginal, dateNew); // Same date; time is ignored. + return StringUtils.equals(dateOriginal, dateNew); // Same date; time is ignored. } private static boolean durationsLookSimilar(FeedMedia media1, FeedMedia media2) { @@ -62,7 +62,7 @@ public class FeedItemDuplicateGuesser { mimeType1 = mimeType1.substring(0, mimeType1.indexOf("/")); mimeType2 = mimeType2.substring(0, mimeType2.indexOf("/")); } - return TextUtils.equals(mimeType1, mimeType2); + return StringUtils.equals(mimeType1, mimeType2); } private static boolean titlesLookSimilar(FeedItem item1, FeedItem item2) { diff --git a/storage/database/src/test/java/de/danoeh/antennapod/storage/database/FeedItemPermutorsTest.java b/storage/database/src/test/java/de/danoeh/antennapod/storage/database/FeedItemPermutorsTest.java new file mode 100644 index 000000000..9e0f106fd --- /dev/null +++ b/storage/database/src/test/java/de/danoeh/antennapod/storage/database/FeedItemPermutorsTest.java @@ -0,0 +1,231 @@ +package de.danoeh.antennapod.storage.database; + +import de.danoeh.antennapod.model.feed.SortOrder; +import de.danoeh.antennapod.storage.database.FeedItemPermutors; +import de.danoeh.antennapod.storage.database.Permutor; +import org.junit.Test; + +import java.util.ArrayList; +import java.util.Calendar; +import java.util.List; + +import de.danoeh.antennapod.model.feed.Feed; +import de.danoeh.antennapod.model.feed.FeedItem; +import de.danoeh.antennapod.model.feed.FeedMedia; + +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; + +/** + * Test class for FeedItemPermutors. + */ +public class FeedItemPermutorsTest { + + @Test + public void testEnsureNonNullPermutors() { + for (SortOrder sortOrder : SortOrder.values()) { + assertNotNull("The permutor for SortOrder " + sortOrder + " is unexpectedly null", + FeedItemPermutors.getPermutor(sortOrder)); + } + } + + @Test + public void testPermutorForRule_EPISODE_TITLE_ASC() { + Permutor<FeedItem> permutor = FeedItemPermutors.getPermutor(SortOrder.EPISODE_TITLE_A_Z); + + List<FeedItem> itemList = getTestList(); + assertTrue(checkIdOrder(itemList, 1, 3, 2)); // before sorting + permutor.reorder(itemList); + assertTrue(checkIdOrder(itemList, 1, 2, 3)); // after sorting + } + + @Test + public void testPermutorForRule_EPISODE_TITLE_ASC_NullTitle() { + Permutor<FeedItem> permutor = FeedItemPermutors.getPermutor(SortOrder.EPISODE_TITLE_A_Z); + + List<FeedItem> itemList = getTestList(); + itemList.get(2) // itemId 2 + .setTitle(null); + assertTrue(checkIdOrder(itemList, 1, 3, 2)); // before sorting + permutor.reorder(itemList); + assertTrue(checkIdOrder(itemList, 2, 1, 3)); // after sorting + } + + + @Test + public void testPermutorForRule_EPISODE_TITLE_DESC() { + Permutor<FeedItem> permutor = FeedItemPermutors.getPermutor(SortOrder.EPISODE_TITLE_Z_A); + + List<FeedItem> itemList = getTestList(); + assertTrue(checkIdOrder(itemList, 1, 3, 2)); // before sorting + permutor.reorder(itemList); + assertTrue(checkIdOrder(itemList, 3, 2, 1)); // after sorting + } + + @Test + public void testPermutorForRule_DATE_ASC() { + Permutor<FeedItem> permutor = FeedItemPermutors.getPermutor(SortOrder.DATE_OLD_NEW); + + List<FeedItem> itemList = getTestList(); + assertTrue(checkIdOrder(itemList, 1, 3, 2)); // before sorting + permutor.reorder(itemList); + assertTrue(checkIdOrder(itemList, 1, 2, 3)); // after sorting + } + + @Test + public void testPermutorForRule_DATE_ASC_NulPubDatel() { + Permutor<FeedItem> permutor = FeedItemPermutors.getPermutor(SortOrder.DATE_OLD_NEW); + + List<FeedItem> itemList = getTestList(); + itemList.get(2) // itemId 2 + .setPubDate(null); + assertTrue(checkIdOrder(itemList, 1, 3, 2)); // before sorting + permutor.reorder(itemList); + assertTrue(checkIdOrder(itemList, 2, 1, 3)); // after sorting + } + + @Test + public void testPermutorForRule_DATE_DESC() { + Permutor<FeedItem> permutor = FeedItemPermutors.getPermutor(SortOrder.DATE_NEW_OLD); + + List<FeedItem> itemList = getTestList(); + assertTrue(checkIdOrder(itemList, 1, 3, 2)); // before sorting + permutor.reorder(itemList); + assertTrue(checkIdOrder(itemList, 3, 2, 1)); // after sorting + } + + @Test + public void testPermutorForRule_DURATION_ASC() { + Permutor<FeedItem> permutor = FeedItemPermutors.getPermutor(SortOrder.DURATION_SHORT_LONG); + + List<FeedItem> itemList = getTestList(); + assertTrue(checkIdOrder(itemList, 1, 3, 2)); // before sorting + permutor.reorder(itemList); + assertTrue(checkIdOrder(itemList, 1, 2, 3)); // after sorting + } + + @Test + public void testPermutorForRule_DURATION_DESC() { + Permutor<FeedItem> permutor = FeedItemPermutors.getPermutor(SortOrder.DURATION_LONG_SHORT); + + List<FeedItem> itemList = getTestList(); + assertTrue(checkIdOrder(itemList, 1, 3, 2)); // before sorting + permutor.reorder(itemList); + assertTrue(checkIdOrder(itemList, 3, 2, 1)); // after sorting + } + + @Test + public void testPermutorForRule_size_asc() { + Permutor<FeedItem> permutor = FeedItemPermutors.getPermutor(SortOrder.SIZE_SMALL_LARGE); + + List<FeedItem> itemList = getTestList(); + assertTrue(checkIdOrder(itemList, 1, 3, 2)); // before sorting + permutor.reorder(itemList); + assertTrue(checkIdOrder(itemList, 1, 2, 3)); // after sorting + } + + @Test + public void testPermutorForRule_size_desc() { + Permutor<FeedItem> permutor = FeedItemPermutors.getPermutor(SortOrder.SIZE_LARGE_SMALL); + + List<FeedItem> itemList = getTestList(); + assertTrue(checkIdOrder(itemList, 1, 3, 2)); // before sorting + permutor.reorder(itemList); + assertTrue(checkIdOrder(itemList, 3, 2, 1)); // after sorting + } + + @Test + public void testPermutorForRule_DURATION_DESC_NullMedia() { + Permutor<FeedItem> permutor = FeedItemPermutors.getPermutor(SortOrder.DURATION_LONG_SHORT); + + List<FeedItem> itemList = getTestList(); + itemList.get(1) // itemId 3 + .setMedia(null); + assertTrue(checkIdOrder(itemList, 1, 3, 2)); // before sorting + permutor.reorder(itemList); + assertTrue(checkIdOrder(itemList, 2, 1, 3)); // after sorting + } + + @Test + public void testPermutorForRule_FEED_TITLE_ASC() { + Permutor<FeedItem> permutor = FeedItemPermutors.getPermutor(SortOrder.FEED_TITLE_A_Z); + + List<FeedItem> itemList = getTestList(); + assertTrue(checkIdOrder(itemList, 1, 3, 2)); // before sorting + permutor.reorder(itemList); + assertTrue(checkIdOrder(itemList, 1, 2, 3)); // after sorting + } + + @Test + public void testPermutorForRule_FEED_TITLE_DESC() { + Permutor<FeedItem> permutor = FeedItemPermutors.getPermutor(SortOrder.FEED_TITLE_Z_A); + + List<FeedItem> itemList = getTestList(); + assertTrue(checkIdOrder(itemList, 1, 3, 2)); // before sorting + permutor.reorder(itemList); + assertTrue(checkIdOrder(itemList, 3, 2, 1)); // after sorting + } + + @Test + public void testPermutorForRule_FEED_TITLE_DESC_NullTitle() { + Permutor<FeedItem> permutor = FeedItemPermutors.getPermutor(SortOrder.FEED_TITLE_Z_A); + + List<FeedItem> itemList = getTestList(); + itemList.get(1) // itemId 3 + .getFeed().setTitle(null); + assertTrue(checkIdOrder(itemList, 1, 3, 2)); // before sorting + permutor.reorder(itemList); + assertTrue(checkIdOrder(itemList, 2, 1, 3)); // after sorting + } + + /** + * Generates a list with test data. + */ + private List<FeedItem> getTestList() { + List<FeedItem> itemList = new ArrayList<>(); + + Calendar calendar = Calendar.getInstance(); + calendar.set(2019, 0, 1); // January 1st + Feed feed1 = new Feed(null, null, "Feed title 1"); + FeedItem feedItem1 = new FeedItem(1, "Title 1", null, null, calendar.getTime(), 0, feed1); + FeedMedia feedMedia1 = new FeedMedia(0, feedItem1, 1000, 0, 100, null, null, null, true, null, 0, 0); + feedItem1.setMedia(feedMedia1); + itemList.add(feedItem1); + + calendar.set(2019, 2, 1); // March 1st + Feed feed2 = new Feed(null, null, "Feed title 3"); + FeedItem feedItem2 = new FeedItem(3, "Title 3", null, null, calendar.getTime(), 0, feed2); + FeedMedia feedMedia2 = new FeedMedia(0, feedItem2, 3000, 0, 300, null, null, null, true, null, 0, 0); + feedItem2.setMedia(feedMedia2); + itemList.add(feedItem2); + + calendar.set(2019, 1, 1); // February 1st + Feed feed3 = new Feed(null, null, "Feed title 2"); + FeedItem feedItem3 = new FeedItem(2, "Title 2", null, null, calendar.getTime(), 0, feed3); + FeedMedia feedMedia3 = new FeedMedia(0, feedItem3, 2000, 0, 200, null, null, null, true, null, 0, 0); + feedItem3.setMedia(feedMedia3); + itemList.add(feedItem3); + + return itemList; + } + + /** + * Checks if both lists have the same size and the same ID order. + * + * @param itemList Item list. + * @param ids List of IDs. + * @return <code>true</code> if both lists have the same size and the same ID order. + */ + private boolean checkIdOrder(List<FeedItem> itemList, long... ids) { + if (itemList.size() != ids.length) { + return false; + } + + for (int i = 0; i < ids.length; i++) { + if (itemList.get(i).getId() != ids[i]) { + return false; + } + } + return true; + } +} diff --git a/storage/database/src/test/java/de/danoeh/antennapod/storage/database/mapper/FeedCursorMapperTest.java b/storage/database/src/test/java/de/danoeh/antennapod/storage/database/mapper/FeedCursorMapperTest.java new file mode 100644 index 000000000..5e7a4843e --- /dev/null +++ b/storage/database/src/test/java/de/danoeh/antennapod/storage/database/mapper/FeedCursorMapperTest.java @@ -0,0 +1,100 @@ +package de.danoeh.antennapod.storage.database.mapper; + +import android.content.ContentValues; +import android.content.Context; +import android.database.Cursor; + +import androidx.test.platform.app.InstrumentationRegistry; + +import de.danoeh.antennapod.storage.database.PodDBAdapter; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.robolectric.RobolectricTestRunner; + +import de.danoeh.antennapod.model.feed.Feed; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +@RunWith(RobolectricTestRunner.class) +public class FeedCursorMapperTest { + private PodDBAdapter adapter; + + @Before + public void setUp() { + Context context = InstrumentationRegistry.getInstrumentation().getContext(); + + PodDBAdapter.init(context); + adapter = PodDBAdapter.getInstance(); + + writeFeedToDatabase(); + } + + @After + public void tearDown() { + PodDBAdapter.tearDownTests(); + } + + @SuppressWarnings("ConstantConditions") + @Test + public void testFromCursor() { + try (Cursor cursor = adapter.getAllFeedsCursor()) { + cursor.moveToNext(); + Feed feed = FeedCursorMapper.convert(cursor); + assertTrue(feed.getId() >= 0); + assertEquals("feed custom title", feed.getTitle()); + assertEquals("feed custom title", feed.getCustomTitle()); + assertEquals("feed link", feed.getLink()); + assertEquals("feed description", feed.getDescription()); + assertEquals("feed payment link", feed.getPaymentLinks().get(0).url); + assertEquals("feed author", feed.getAuthor()); + assertEquals("feed language", feed.getLanguage()); + assertEquals("feed image url", feed.getImageUrl()); + assertEquals("feed file url", feed.getLocalFileUrl()); + assertEquals("feed download url", feed.getDownloadUrl()); + assertEquals(42, feed.getLastRefreshAttempt()); + assertEquals("feed last update", feed.getLastModified()); + assertEquals("feed type", feed.getType()); + assertEquals("feed identifier", feed.getFeedIdentifier()); + assertTrue(feed.isPaged()); + assertEquals("feed next page link", feed.getNextPageLink()); + assertTrue(feed.getItemFilter().showUnplayed); + assertEquals(1, feed.getSortOrder().code); + assertTrue(feed.hasLastUpdateFailed()); + } + } + + /** + * Insert test data to the database. + * Uses raw database insert instead of adapter.setCompleteFeed() to avoid testing the Feed class + * against itself. + */ + private void writeFeedToDatabase() { + ContentValues values = new ContentValues(); + values.put(PodDBAdapter.KEY_TITLE, "feed title"); + values.put(PodDBAdapter.KEY_CUSTOM_TITLE, "feed custom title"); + values.put(PodDBAdapter.KEY_LINK, "feed link"); + values.put(PodDBAdapter.KEY_DESCRIPTION, "feed description"); + values.put(PodDBAdapter.KEY_PAYMENT_LINK, "feed payment link"); + values.put(PodDBAdapter.KEY_AUTHOR, "feed author"); + values.put(PodDBAdapter.KEY_LANGUAGE, "feed language"); + values.put(PodDBAdapter.KEY_IMAGE_URL, "feed image url"); + + values.put(PodDBAdapter.KEY_FILE_URL, "feed file url"); + values.put(PodDBAdapter.KEY_DOWNLOAD_URL, "feed download url"); + values.put(PodDBAdapter.KEY_LAST_REFRESH_ATTEMPT, 42); + values.put(PodDBAdapter.KEY_LASTUPDATE, "feed last update"); + values.put(PodDBAdapter.KEY_TYPE, "feed type"); + values.put(PodDBAdapter.KEY_FEED_IDENTIFIER, "feed identifier"); + + values.put(PodDBAdapter.KEY_IS_PAGED, true); + values.put(PodDBAdapter.KEY_NEXT_PAGE_LINK, "feed next page link"); + values.put(PodDBAdapter.KEY_HIDE, "unplayed"); + values.put(PodDBAdapter.KEY_SORT_ORDER, "1"); + values.put(PodDBAdapter.KEY_LAST_UPDATE_FAILED, true); + + adapter.insertTestData(PodDBAdapter.TABLE_NAME_FEEDS, values); + } +} |