Prechádzať zdrojové kódy

Initial commit for categories

inorichi 9 rokov pred
rodič
commit
1c4b5b3a72

+ 102 - 4
app/src/main/java/eu/kanade/mangafeed/data/database/DatabaseHelper.java

@@ -16,23 +16,34 @@ import com.pushtorefresh.storio.sqlite.queries.RawQuery;
 
 import java.util.List;
 
-import eu.kanade.mangafeed.data.database.models.MangaSync;
-import eu.kanade.mangafeed.data.mangasync.base.MangaSyncService;
+import eu.kanade.mangafeed.data.database.models.Category;
+import eu.kanade.mangafeed.data.database.models.CategoryStorIOSQLiteDeleteResolver;
+import eu.kanade.mangafeed.data.database.models.CategoryStorIOSQLiteGetResolver;
+import eu.kanade.mangafeed.data.database.models.CategoryStorIOSQLitePutResolver;
 import eu.kanade.mangafeed.data.database.models.Chapter;
 import eu.kanade.mangafeed.data.database.models.ChapterStorIOSQLiteDeleteResolver;
 import eu.kanade.mangafeed.data.database.models.ChapterStorIOSQLiteGetResolver;
 import eu.kanade.mangafeed.data.database.models.ChapterStorIOSQLitePutResolver;
 import eu.kanade.mangafeed.data.database.models.Manga;
+import eu.kanade.mangafeed.data.database.models.MangaCategory;
+import eu.kanade.mangafeed.data.database.models.MangaCategoryStorIOSQLiteDeleteResolver;
+import eu.kanade.mangafeed.data.database.models.MangaCategoryStorIOSQLiteGetResolver;
+import eu.kanade.mangafeed.data.database.models.MangaCategoryStorIOSQLitePutResolver;
 import eu.kanade.mangafeed.data.database.models.MangaStorIOSQLiteDeleteResolver;
 import eu.kanade.mangafeed.data.database.models.MangaStorIOSQLiteGetResolver;
 import eu.kanade.mangafeed.data.database.models.MangaStorIOSQLitePutResolver;
+import eu.kanade.mangafeed.data.database.models.MangaSync;
 import eu.kanade.mangafeed.data.database.models.MangaSyncStorIOSQLiteDeleteResolver;
 import eu.kanade.mangafeed.data.database.models.MangaSyncStorIOSQLiteGetResolver;
 import eu.kanade.mangafeed.data.database.models.MangaSyncStorIOSQLitePutResolver;
+import eu.kanade.mangafeed.data.database.resolvers.LibraryMangaGetResolver;
 import eu.kanade.mangafeed.data.database.resolvers.MangaWithUnreadGetResolver;
-import eu.kanade.mangafeed.data.database.tables.MangaSyncTable;
+import eu.kanade.mangafeed.data.database.tables.CategoryTable;
 import eu.kanade.mangafeed.data.database.tables.ChapterTable;
+import eu.kanade.mangafeed.data.database.tables.MangaCategoryTable;
+import eu.kanade.mangafeed.data.database.tables.MangaSyncTable;
 import eu.kanade.mangafeed.data.database.tables.MangaTable;
+import eu.kanade.mangafeed.data.mangasync.base.MangaSyncService;
 import eu.kanade.mangafeed.util.ChapterRecognition;
 import eu.kanade.mangafeed.util.PostResult;
 import rx.Observable;
@@ -60,6 +71,16 @@ public class DatabaseHelper {
                         .getResolver(new MangaSyncStorIOSQLiteGetResolver())
                         .deleteResolver(new MangaSyncStorIOSQLiteDeleteResolver())
                         .build())
+                .addTypeMapping(Category.class, SQLiteTypeMapping.<Category>builder()
+                        .putResolver(new CategoryStorIOSQLitePutResolver())
+                        .getResolver(new CategoryStorIOSQLiteGetResolver())
+                        .deleteResolver(new CategoryStorIOSQLiteDeleteResolver())
+                        .build())
+                .addTypeMapping(MangaCategory.class, SQLiteTypeMapping.<MangaCategory>builder()
+                        .putResolver(new MangaCategoryStorIOSQLitePutResolver())
+                        .getResolver(new MangaCategoryStorIOSQLiteGetResolver())
+                        .deleteResolver(new MangaCategoryStorIOSQLiteDeleteResolver())
+                        .build())
                 .build();
     }
 
@@ -79,6 +100,37 @@ public class DatabaseHelper {
             MangaTable.COLUMN_TITLE
     );
 
+    private final String libraryMangaQuery = String.format(
+            "SELECT M.*, COALESCE(MC.%10$s, 0) AS %12$s " +
+            "FROM (" +
+                "SELECT %1$s.*, COALESCE(C.unread, 0) AS %6$s " +
+                "FROM %1$s " +
+                "LEFT JOIN (" +
+                    "SELECT %5$s, COUNT(*) AS unread " +
+                    "FROM %2$s " +
+                    "WHERE %7$s = 0 " +
+                    "GROUP BY %5$s" +
+                ") AS C " +
+                "ON %4$s = C.%5$s " +
+                "WHERE %8$s = 1 " +
+                "GROUP BY %4$s " +
+                "ORDER BY %9$s" +
+            ") AS M " +
+            "LEFT JOIN (SELECT * FROM %3$s) AS MC ON MC.%11$s = M.%4$s",
+            MangaTable.TABLE,
+            ChapterTable.TABLE,
+            MangaCategoryTable.TABLE,
+            MangaTable.COLUMN_ID,
+            ChapterTable.COLUMN_MANGA_ID,
+            MangaTable.COLUMN_UNREAD,
+            ChapterTable.COLUMN_READ,
+            MangaTable.COLUMN_FAVORITE,
+            MangaTable.COLUMN_TITLE,
+            MangaCategoryTable.COLUMN_CATEGORY_ID,
+            MangaCategoryTable.COLUMN_MANGA_ID,
+            MangaTable.COLUMN_CATEGORY
+    );
+
     public PreparedGetListOfObjects<Manga> getMangas() {
         return db.get()
                 .listOfObjects(Manga.class)
@@ -95,7 +147,18 @@ public class DatabaseHelper {
                         .query(favoriteMangasWithUnreadQuery)
                         .observesTables(MangaTable.TABLE, ChapterTable.TABLE)
                         .build())
-                .withGetResolver(MangaWithUnreadGetResolver.instance)
+                .withGetResolver(MangaWithUnreadGetResolver.INSTANCE)
+                .prepare();
+    }
+
+    public PreparedGetListOfObjects<Manga> getLibraryMangas() {
+        return db.get()
+                .listOfObjects(Manga.class)
+                .withQuery(RawQuery.builder()
+                        .query(libraryMangaQuery)
+                        .observesTables(MangaTable.TABLE, ChapterTable.TABLE, CategoryTable.TABLE)
+                        .build())
+                .withGetResolver(LibraryMangaGetResolver.INSTANCE)
                 .prepare();
     }
 
@@ -337,4 +400,39 @@ public class DatabaseHelper {
                 .object(manga)
                 .prepare();
     }
+
+    // Categories related queries
+
+    public PreparedGetListOfObjects<Category> getCategories() {
+        return db.get()
+                .listOfObjects(Category.class)
+                .withQuery(Query.builder()
+                        .table(CategoryTable.TABLE)
+                        .build())
+                .prepare();
+    }
+
+    public PreparedPutObject<Category> insertCategory(Category category) {
+        return db.put()
+                .object(category)
+                .prepare();
+    }
+
+    public PreparedDeleteObject<Category> deleteCategory(Category category) {
+        return db.delete()
+                .object(category)
+                .prepare();
+    }
+
+    public PreparedPutObject<MangaCategory> insertMangaCategory(MangaCategory mangaCategory) {
+        return db.put()
+                .object(mangaCategory)
+                .prepare();
+    }
+
+    public PreparedPutCollectionOfObjects<MangaCategory> insertMangasCategory(List<MangaCategory> mangasCategory) {
+        return db.put()
+                .objects(mangasCategory)
+                .prepare();
+    }
 }

+ 12 - 4
app/src/main/java/eu/kanade/mangafeed/data/database/DbOpenHelper.java

@@ -5,6 +5,8 @@ import android.database.sqlite.SQLiteDatabase;
 import android.database.sqlite.SQLiteOpenHelper;
 import android.support.annotation.NonNull;
 
+import eu.kanade.mangafeed.data.database.tables.CategoryTable;
+import eu.kanade.mangafeed.data.database.tables.MangaCategoryTable;
 import eu.kanade.mangafeed.data.database.tables.MangaSyncTable;
 import eu.kanade.mangafeed.data.database.tables.ChapterTable;
 import eu.kanade.mangafeed.data.database.tables.MangaTable;
@@ -12,7 +14,7 @@ import eu.kanade.mangafeed.data.database.tables.MangaTable;
 public class DbOpenHelper extends SQLiteOpenHelper {
 
     public static final String DATABASE_NAME = "mangafeed.db";
-    public static final int DATABASE_VERSION = 3;
+    public static final int DATABASE_VERSION = 1;
 
     public DbOpenHelper(@NonNull Context context) {
         super(context, DATABASE_NAME, null, DATABASE_VERSION);
@@ -23,16 +25,22 @@ public class DbOpenHelper extends SQLiteOpenHelper {
         db.execSQL(MangaTable.getCreateTableQuery());
         db.execSQL(ChapterTable.getCreateTableQuery());
         db.execSQL(MangaSyncTable.getCreateTableQuery());
+        db.execSQL(CategoryTable.getCreateTableQuery());
+        db.execSQL(MangaCategoryTable.getCreateTableQuery());
+
+        // DB indexes
+        db.execSQL(MangaTable.getCreateUrlIndexQuery());
+        db.execSQL(MangaTable.getCreateFavoriteIndexQuery());
+        db.execSQL(ChapterTable.getCreateMangaIdIndexQuery());
     }
 
     @Override
     public void onUpgrade(@NonNull SQLiteDatabase db, int oldVersion, int newVersion) {
-        if (oldVersion < 3)
-            db.execSQL(MangaSyncTable.getCreateTableQuery());
+
     }
 
     @Override
-    public void onConfigure(SQLiteDatabase db){
+    public void onConfigure(@NonNull SQLiteDatabase db) {
         db.setForeignKeyConstraintsEnabled(true);
     }
 

+ 26 - 0
app/src/main/java/eu/kanade/mangafeed/data/database/models/Category.java

@@ -0,0 +1,26 @@
+package eu.kanade.mangafeed.data.database.models;
+
+import com.pushtorefresh.storio.sqlite.annotations.StorIOSQLiteColumn;
+import com.pushtorefresh.storio.sqlite.annotations.StorIOSQLiteType;
+
+import java.io.Serializable;
+
+import eu.kanade.mangafeed.data.database.tables.CategoryTable;
+
+@StorIOSQLiteType(table = CategoryTable.TABLE)
+public class Category implements Serializable {
+
+    @StorIOSQLiteColumn(name = CategoryTable.COLUMN_ID, key = true)
+    public Long id;
+
+    @StorIOSQLiteColumn(name = CategoryTable.COLUMN_NAME)
+    public String name;
+
+    public Category() {}
+
+    public static Category create(String name) {
+        Category c = new Category();
+        c.name = name;
+        return c;
+    }
+}

+ 0 - 1
app/src/main/java/eu/kanade/mangafeed/data/database/models/Chapter.java

@@ -40,7 +40,6 @@ public class Chapter implements Serializable {
 
     public int status;
 
-
     public Chapter() {}
 
     public void setUrl(String url) {

+ 5 - 4
app/src/main/java/eu/kanade/mangafeed/data/database/models/Manga.java

@@ -36,7 +36,7 @@ public class Manga implements Serializable {
     public String title;
 
     @StorIOSQLiteColumn(name = MangaTable.COLUMN_STATUS)
-    public String status;
+    public int status;
 
     @StorIOSQLiteColumn(name = MangaTable.COLUMN_THUMBNAIL_URL)
     public String thumbnail_url;
@@ -58,6 +58,8 @@ public class Manga implements Serializable {
 
     public int unread;
 
+    public long category;
+
     public Manga() {}
 
     public void setUrl(String url) {
@@ -83,12 +85,11 @@ public class Manga implements Serializable {
         if (network.genre != null)
             local.genre = network.genre;
 
-        if (network.status != null)
-            local.status = network.status;
-
         if (network.thumbnail_url != null)
             local.thumbnail_url = network.thumbnail_url;
 
+        local.status = network.status;
+
         local.initialized = true;
 
     }

+ 29 - 0
app/src/main/java/eu/kanade/mangafeed/data/database/models/MangaCategory.java

@@ -0,0 +1,29 @@
+package eu.kanade.mangafeed.data.database.models;
+
+import com.pushtorefresh.storio.sqlite.annotations.StorIOSQLiteColumn;
+import com.pushtorefresh.storio.sqlite.annotations.StorIOSQLiteType;
+
+import eu.kanade.mangafeed.data.database.tables.MangaCategoryTable;
+
+@StorIOSQLiteType(table = MangaCategoryTable.TABLE)
+public class MangaCategory {
+
+    @StorIOSQLiteColumn(name = MangaCategoryTable.COLUMN_ID, key = true)
+    public Long id;
+
+    @StorIOSQLiteColumn(name = MangaCategoryTable.COLUMN_MANGA_ID)
+    public long manga_id;
+
+    @StorIOSQLiteColumn(name = MangaCategoryTable.COLUMN_CATEGORY_ID)
+    public long category_id;
+
+    public MangaCategory() {}
+
+    public static MangaCategory create(Manga manga, Category category) {
+        MangaCategory mc = new MangaCategory();
+        mc.manga_id = manga.id;
+        mc.category_id = category.id;
+        return mc;
+    }
+
+}

+ 28 - 0
app/src/main/java/eu/kanade/mangafeed/data/database/resolvers/LibraryMangaGetResolver.java

@@ -0,0 +1,28 @@
+package eu.kanade.mangafeed.data.database.resolvers;
+
+import android.database.Cursor;
+import android.support.annotation.NonNull;
+
+import eu.kanade.mangafeed.data.database.models.Manga;
+import eu.kanade.mangafeed.data.database.models.MangaStorIOSQLiteGetResolver;
+import eu.kanade.mangafeed.data.database.tables.MangaTable;
+
+public class LibraryMangaGetResolver extends MangaStorIOSQLiteGetResolver {
+
+    public static final LibraryMangaGetResolver INSTANCE = new LibraryMangaGetResolver();
+
+    @Override
+    @NonNull
+    public Manga mapFromCursor(@NonNull Cursor cursor) {
+        Manga manga = super.mapFromCursor(cursor);
+
+        int unreadColumn = cursor.getColumnIndex(MangaTable.COLUMN_UNREAD);
+        manga.unread = cursor.getInt(unreadColumn);
+
+        int categoryColumn = cursor.getColumnIndex(MangaTable.COLUMN_CATEGORY);
+        manga.category = cursor.getLong(categoryColumn);
+
+        return manga;
+    }
+
+}

+ 1 - 1
app/src/main/java/eu/kanade/mangafeed/data/database/resolvers/MangaWithUnreadGetResolver.java

@@ -9,7 +9,7 @@ import eu.kanade.mangafeed.data.database.tables.MangaTable;
 
 public class MangaWithUnreadGetResolver extends MangaStorIOSQLiteGetResolver {
 
-    public static final MangaWithUnreadGetResolver instance = new MangaWithUnreadGetResolver();
+    public static final MangaWithUnreadGetResolver INSTANCE = new MangaWithUnreadGetResolver();
 
     @Override
     @NonNull

+ 16 - 0
app/src/main/java/eu/kanade/mangafeed/data/database/tables/CategoryTable.java

@@ -12,4 +12,20 @@ public class CategoryTable {
 
     @NonNull
     public static final String COLUMN_NAME = "name";
+
+    // This is just class with Meta Data, we don't need instances
+    private CategoryTable() {
+        throw new IllegalStateException("No instances please");
+    }
+
+    // Better than static final field -> allows VM to unload useless String
+    // Because you need this string only once per application life on the device
+    @NonNull
+    public static String getCreateTableQuery() {
+        return "CREATE TABLE " + TABLE + "("
+                + COLUMN_ID + " INTEGER NOT NULL PRIMARY KEY, "
+                + COLUMN_NAME + " TEXT NOT NULL"
+                + ");";
+
+    }
 }

+ 6 - 2
app/src/main/java/eu/kanade/mangafeed/data/database/tables/ChapterTable.java

@@ -48,8 +48,12 @@ public class ChapterTable {
 				+ COLUMN_DATE_UPLOAD + " LONG NOT NULL, "
 				+ "FOREIGN KEY(" + COLUMN_MANGA_ID + ") REFERENCES " + MangaTable.TABLE + "(" + MangaTable.COLUMN_ID + ") "
 				+ "ON DELETE CASCADE"
-				+ ");"
-				+ "CREATE INDEX " + TABLE + "_" + COLUMN_MANGA_ID + "_index ON " + TABLE + "(" + COLUMN_MANGA_ID + ");";
+				+ ");";
+	}
+
+	public static String getCreateMangaIdIndexQuery() {
+		return "CREATE INDEX " + TABLE + "_" + COLUMN_MANGA_ID + "_index ON " + TABLE + "(" + COLUMN_MANGA_ID + ");";
+
 	}
 	
 }

+ 27 - 2
app/src/main/java/eu/kanade/mangafeed/data/database/tables/MangaCategoryTable.java

@@ -8,8 +8,33 @@ public class MangaCategoryTable {
     public static final String TABLE = "mangas_categories";
 
     @NonNull
-    public static final String COLUMN_MANGA_ID = "_manga_id";
+    public static final String COLUMN_ID = "_id";
 
     @NonNull
-    public static final String COLUMN_CATEGORY_ID = "_category_id";
+    public static final String COLUMN_MANGA_ID = "manga_id";
+
+    @NonNull
+    public static final String COLUMN_CATEGORY_ID = "category_id";
+
+    // This is just class with Meta Data, we don't need instances
+    private MangaCategoryTable() {
+        throw new IllegalStateException("No instances please");
+    }
+
+    // Better than static final field -> allows VM to unload useless String
+    // Because you need this string only once per application life on the device
+    @NonNull
+    public static String getCreateTableQuery() {
+        return "CREATE TABLE " + TABLE + "("
+                + COLUMN_ID + " INTEGER NOT NULL PRIMARY KEY, "
+                + COLUMN_MANGA_ID + " INTEGER NOT NULL, "
+                + COLUMN_CATEGORY_ID + " INTEGER NOT NULL, "
+                + "FOREIGN KEY(" + COLUMN_CATEGORY_ID + ") REFERENCES " + CategoryTable.TABLE + "(" + CategoryTable.COLUMN_ID + ") "
+                + "ON DELETE CASCADE, "
+                + "FOREIGN KEY(" + COLUMN_MANGA_ID + ") REFERENCES " + MangaTable.TABLE + "(" + MangaTable.COLUMN_ID + ") "
+                + "ON DELETE CASCADE"
+                + ");";
+
+    }
+
 }

+ 15 - 4
app/src/main/java/eu/kanade/mangafeed/data/database/tables/MangaTable.java

@@ -50,11 +50,14 @@ public class MangaTable {
     public static final String COLUMN_VIEWER = "viewer";
 
     @NonNull
-    public static final String COLUMN_CHAPTER_FLAGS = "chapter_order";
+    public static final String COLUMN_CHAPTER_FLAGS = "chapter_flags";
 
     @NonNull
     public static final String COLUMN_UNREAD = "unread";
 
+    @NonNull
+    public static final String COLUMN_CATEGORY = "category";
+
     // This is just class with Meta Data, we don't need instances
     private MangaTable() {
         throw new IllegalStateException("No instances please");
@@ -73,15 +76,23 @@ public class MangaTable {
                 + COLUMN_DESCRIPTION + " TEXT, "
                 + COLUMN_GENRE + " TEXT, "
                 + COLUMN_TITLE + " TEXT NOT NULL, "
-                + COLUMN_STATUS + " TEXT, "
+                + COLUMN_STATUS + " INTEGER NOT NULL, "
                 + COLUMN_THUMBNAIL_URL + " TEXT, "
                 + COLUMN_FAVORITE + " INTEGER NOT NULL, "
                 + COLUMN_LAST_UPDATE + " LONG, "
                 + COLUMN_INITIALIZED + " BOOLEAN NOT NULL, "
                 + COLUMN_VIEWER + " INTEGER NOT NULL, "
                 + COLUMN_CHAPTER_FLAGS + " INTEGER NOT NULL"
-                + ");"
-                + "CREATE INDEX " + TABLE + "_" + COLUMN_URL + "_index ON " + TABLE + "(" + COLUMN_URL + ");";
+                + ");";
+
+    }
+
+    public static String getCreateUrlIndexQuery() {
+        return "CREATE INDEX " + TABLE + "_" + COLUMN_URL + "_index ON " + TABLE + "(" + COLUMN_URL + ");";
+    }
+
+    public static String getCreateFavoriteIndexQuery() {
+        return "CREATE INDEX " + TABLE + "_" + COLUMN_FAVORITE + "_index ON " + TABLE + "(" + COLUMN_FAVORITE + ");";
 
     }
 }

+ 1 - 1
app/src/main/java/eu/kanade/mangafeed/data/source/online/english/Batoto.java

@@ -296,7 +296,7 @@ public class Batoto extends Source {
 
         boolean fieldCompleted = unparsedHtml.contains("<td>Complete</td>");
         //TODO fix
-        newManga.status = fieldCompleted + "";
+        newManga.status = 0;
 
         newManga.initialized = true;
 

+ 2 - 1
app/src/main/java/eu/kanade/mangafeed/data/source/online/english/Mangahere.java

@@ -249,7 +249,8 @@ public class Mangahere extends Source {
         }
         if (statusElement != null) {
             boolean fieldCompleted = statusElement.text().contains("Completed");
-            newManga.status = fieldCompleted + "";
+            // TODO fix status
+//            newManga.status = fieldCompleted + "";
         }
 
         beginIndex = unparsedHtml.indexOf("<img");

+ 12 - 0
app/src/main/java/eu/kanade/mangafeed/ui/library/LibraryPresenter.java

@@ -1,6 +1,10 @@
 package eu.kanade.mangafeed.ui.library;
 
 import android.os.Bundle;
+import android.util.Pair;
+
+import java.util.List;
+import java.util.Map;
 
 import javax.inject.Inject;
 
@@ -44,4 +48,12 @@ public class LibraryPresenter extends BasePresenter<LibraryFragment> {
                 .subscribe());
     }
 
+    public Observable<Map<Long, List<Manga>>> getLibraryMangasObservable() {
+        return db.getLibraryMangas().createObservable()
+                .flatMap(mangas -> Observable.from(mangas)
+                        .groupBy(manga -> manga.category)
+                        .flatMap(group -> group.toList().map(list -> new Pair<>(group.getKey(), list)))
+                        .toMap(pair -> pair.first, pair -> pair.second));
+    }
+
 }

+ 119 - 0
app/src/test/java/eu/kanade/mangafeed/CategoryTest.java

@@ -0,0 +1,119 @@
+package eu.kanade.mangafeed;
+
+import android.app.Application;
+import android.os.Build;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.RobolectricGradleTestRunner;
+import org.robolectric.RuntimeEnvironment;
+import org.robolectric.annotation.Config;
+
+import java.util.List;
+
+import eu.kanade.mangafeed.data.database.DatabaseHelper;
+import eu.kanade.mangafeed.data.database.models.Category;
+import eu.kanade.mangafeed.data.database.models.Manga;
+import eu.kanade.mangafeed.data.database.models.MangaCategory;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.hasSize;
+import static org.hamcrest.Matchers.is;
+import static org.hamcrest.Matchers.not;
+
+@Config(constants = BuildConfig.class, sdk = Build.VERSION_CODES.LOLLIPOP)
+@RunWith(RobolectricGradleTestRunner.class)
+public class CategoryTest {
+
+    DatabaseHelper db;
+
+    @Before
+    public void setup() {
+        Application app = RuntimeEnvironment.application;
+        db = new DatabaseHelper(app);
+
+        // Create 5 mangas
+        createManga("a");
+        createManga("b");
+        createManga("c");
+        createManga("d");
+        createManga("e");
+    }
+
+    @Test
+    public void testHasCategories() {
+        // Create 2 categories
+        createCategory("Reading");
+        createCategory("Hold");
+
+        List<Category> categories = db.getCategories().executeAsBlocking();
+        assertThat(categories, hasSize(2));
+    }
+
+    @Test
+    public void testHasLibraryMangas() {
+        List<Manga> mangas = db.getLibraryMangas().executeAsBlocking();
+        assertThat(mangas, hasSize(5));
+    }
+
+    @Test
+    public void testHasCorrectFavorites() {
+        Manga m = new Manga();
+        m.title = "title";
+        m.author = "";
+        m.artist = "";
+        m.thumbnail_url = "";
+        m.genre = "a list of genres";
+        m.description = "long description";
+        m.url = "url to manga";
+        m.favorite = false;
+        db.insertManga(m).executeAsBlocking();
+        List<Manga> mangas = db.getLibraryMangas().executeAsBlocking();
+        assertThat(mangas, hasSize(5));
+    }
+
+    @Test
+    public void testMangaInCategory() {
+        // Create 2 categories
+        createCategory("Reading");
+        createCategory("Hold");
+
+        // It should not have 0 as id
+        Category c = db.getCategories().executeAsBlocking().get(0);
+        assertThat(c.id, not(0));
+
+        // Add a manga to a category
+        Manga m = db.getMangas().executeAsBlocking().get(0);
+        MangaCategory mc = MangaCategory.create(m, c);
+        db.insertMangaCategory(mc).executeAsBlocking();
+
+        // Get mangas from library and assert manga category is the same
+        List<Manga> mangas = db.getLibraryMangas().executeAsBlocking();
+        for (Manga manga : mangas) {
+            if (manga.id.equals(m.id)) {
+                assertThat(manga.category, is(c.id));
+            }
+        }
+    }
+
+    private void createManga(String title) {
+        Manga m = new Manga();
+        m.title = title;
+        m.author = "";
+        m.artist = "";
+        m.thumbnail_url = "";
+        m.genre = "a list of genres";
+        m.description = "long description";
+        m.url = "url to manga";
+        m.favorite = true;
+        db.insertManga(m).executeAsBlocking();
+    }
+
+    private void createCategory(String name) {
+        Category c = new Category();
+        c.name = name;
+        db.insertCategory(c).executeAsBlocking();
+    }
+
+}