Unit Test the Database (#758)

* Add TODOs for BookDatabaseTest

* minor change to BookDatabaseTest

* add TODOs for BookmarksDatabaseTest

* add TODOs for BookmarksDatabaseTest

* Add TODOs for networkLanguageDatabaseTest

* add TODOs for RecentSearchDatabaseTest

* Approach not working. new attempt required

* stuck trying to access the database using overridden mocked DAO class. New way to do the stuff

* able to access the database

* two conflicting databases created. need to fix

* fix a bug due to pass by value and not by reference

* remove redundant code

* separate the internal logic and the DAO wrapper in BookDao class

* intial draft working

* create test for BookDao.getBooks()

test has minor bug that needs to be rectified

* internal BookDao methods returning null values during testing. needs to be fixed

* Add TODOs for testing utils/files/FileUtils

* Add tests for utils/files/FileUtils.java

* Add tests for RecentSearchDatabaseTest

* fix travis build failure

the file NetworkLanguageDatabase test contains no test and is deleted

* Add comments to RecentSearchDatabaseTest

* minor formatting changes

* delete FileUtilsTest

* changed access type of methods as private

* delete extra unnecessary code

* need to fix a powermock bug

* fix the file.exists() error

* totally fix the file.exists() issue

* fix the File.exists() issue

* update Databas tests

* commenting all code and checking whether travis passes

* fix all travis build errors

* improve the test structure

* update tests

* remove unused import statements

* fix spacing

* comment test to find bug

* test if build works
This commit is contained in:
Siddharth Sharma 2018-06-15 21:22:02 +05:30 committed by Isaac Hutt
parent c97420cd04
commit f47bd50f37
3 changed files with 270 additions and 4 deletions

View File

@ -0,0 +1,192 @@
/*
* Kiwix Android
* Copyright (C) 2018 Kiwix <android.kiwix.org>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.kiwix.kiwixmobile.data.local;
import android.content.Context;
import android.support.test.InstrumentationRegistry;
import android.support.test.runner.AndroidJUnit4;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.kiwix.kiwixmobile.data.local.dao.BookDao;
import org.kiwix.kiwixmobile.data.local.entity.BookDatabaseEntity;
import org.kiwix.kiwixmobile.library.entity.LibraryNetworkEntity.Book;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import static org.junit.Assert.assertEquals;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@RunWith(AndroidJUnit4.class)
public class BookDatabaseTest {
private Context context;
private @Mock KiwixDatabase kiwixDatabase;
private BookDao bookDao;
private boolean mockInitialized = false;
private File testDir;
@Before
public void executeBefore() {
if (!mockInitialized) {
MockitoAnnotations.initMocks(this);
mockInitialized = true;
}
context = InstrumentationRegistry.getTargetContext();
//kiwixDatabase = new KiwixDatabase(context);
bookDao = new BookDao(kiwixDatabase);
// Create a temporary directory where all the test files will be saved
testDir = context.getDir("testDir", context.MODE_PRIVATE);
}
//TODO : test books are saved after downloading the list of available zim files
@Test
public void testGetBooks() throws IOException {
// Save the fake data to test
String testId = "6qq5301d-2cr0-ebg5-474h-6db70j52864p";
String fileName = testDir.getPath() + "/" + testId + "testFile";
ArrayList<Book> booksToAdd = getFakeData(fileName);
// Set up the mocks
when(kiwixDatabase.deleteWhere(any(), any())).thenReturn(0);
// Get the filtered book list from the database (using the internal selection logic in BookDao)
ArrayList<Book> booksRetrieved = bookDao.filterBookResults(booksToAdd);
// Test whether the correct books are returned
// Filename ends with .zim and the file exists in memory
if(!booksRetrieved.contains(booksToAdd.get(0))) assertEquals(0, 1);
verify(kiwixDatabase, never()).deleteWhere(BookDatabaseEntity.class, BookDatabaseEntity.URL.eq(booksToAdd.get(0).file.getPath()));
// Filename ends with .part and the file exists in memory
if(booksRetrieved.contains(booksToAdd.get(1))) assertEquals(0, 1);
verify(kiwixDatabase, never()).deleteWhere(BookDatabaseEntity.class, BookDatabaseEntity.URL.eq(booksToAdd.get(1).file.getPath()));
// Filename ends with .zim, however only the .zim.part file exists in memory
if(booksRetrieved.contains(booksToAdd.get(2))) assertEquals(0, 1);
verify(kiwixDatabase, never()).deleteWhere(BookDatabaseEntity.class, BookDatabaseEntity.URL.eq(booksToAdd.get(2).file.getPath()));
// Filename ends with .zim but neither the .zim, nor the .zim.part file exists in memory
if(booksRetrieved.contains(booksToAdd.get(3))) assertEquals(0, 1);
verify(kiwixDatabase).deleteWhere(BookDatabaseEntity.class, BookDatabaseEntity.URL.eq(booksToAdd.get(3).file.getPath()));
// Filename ends with .zim and both the .zim, and the .zim.part files exists in memory
if(!booksRetrieved.contains(booksToAdd.get(4))) assertEquals(0, 1);
verify(kiwixDatabase, never()).deleteWhere(BookDatabaseEntity.class, BookDatabaseEntity.URL.eq(booksToAdd.get(4).file.getPath()));
// If the filename ends with .zimXX
// FileName.zimXX.part does not exist for any value of "XX" from "aa" till "dr", but FileName.zimXX exists for all "XX" from "aa', till "ds", then it does not exist
// Also, the file inside the BooksToAdd does exist in memory
if(!booksRetrieved.contains(booksToAdd.get(5))) assertEquals(0, 1);
verify(kiwixDatabase, never()).deleteWhere(BookDatabaseEntity.class, BookDatabaseEntity.URL.eq(booksToAdd.get(5).file.getPath()));
// FileName.zimXX.part does not exist for any value of "XX" from "aa" till "dr", but FileName.zimXX exists for all "XX" from "aa', till "ds", then it does not exist
// Also, the file inside the BooksToAdd also not exist in memory
if(booksRetrieved.contains(booksToAdd.get(6))) assertEquals(0, 1);
verify(kiwixDatabase).deleteWhere(BookDatabaseEntity.class, BookDatabaseEntity.URL.eq(booksToAdd.get(6).file.getPath()));
// FileName.zimXX.part exists for some "XX" between "aa" till "bl"
// And FileName.zimXX exists for all "XX" from "aa', till "bk", and then it does not exist
// Also, the file inside the BooksToAdd does exist in memory
if(!booksRetrieved.contains(booksToAdd.get(7))) assertEquals(0, 1);
verify(kiwixDatabase, never()).deleteWhere(BookDatabaseEntity.class, BookDatabaseEntity.URL.eq(booksToAdd.get(7).file.getPath()));
// FileName.zimXX.part exists for some "XX" between "aa" till "bl"
// And FileName.zimXX exists for all "XX" from "aa', till "bk", and then it does not exist
// Also, the file inside the BooksToAdd does not exist in memory
if(booksRetrieved.contains(booksToAdd.get(8))) assertEquals(0, 1);
verify(kiwixDatabase).deleteWhere(BookDatabaseEntity.class, BookDatabaseEntity.URL.eq(booksToAdd.get(8).file.getPath()));
}
private ArrayList<Book> getFakeData(String baseFileName) throws IOException {
ArrayList<Book> books = new ArrayList<>();
for(int i = 0; i < 9; i++){
Book book = new Book();
book.bookName = "Test Copy " + Integer.toString(i);
book.id = "Test ID " + Integer.toString(i);
String fileName = baseFileName + Integer.toString(i);
switch (i) {
case 0: book.file = new File(fileName + ".zim"); book.file.createNewFile(); break;
case 1: book.file = new File(fileName + ".part"); book.file.createNewFile(); break;
case 2: book.file = new File(fileName + ".zim");
File t2 = new File(fileName + ".zim.part"); t2.createNewFile(); break;
case 3: book.file = new File(fileName + ".zim"); break;
case 4: book.file = new File(fileName + ".zim"); book.file.createNewFile();
File t4 = new File(fileName + ".zim.part"); t4.createNewFile(); break;
case 5: book.file = new File(fileName + ".zimdg"); setupCase1(fileName); break;
case 6: book.file = new File(fileName + ".zimyr"); setupCase2(fileName); break;
case 7: book.file = new File(fileName + ".zimdg"); setupCase1(fileName); break;
case 8: book.file = new File(fileName + ".zimyr"); setupCase2(fileName); break;
}
books.add(book);
}
return books;
}
private void setupCase1(String fileName) throws IOException {
for (char char1 = 'a'; char1 <= 'z'; char1++) {
for (char char2 = 'a'; char2 <= 'z'; char2++) {
File file = new File(fileName + ".zim" + char1 + char2);
file.createNewFile();
if (char1 == 'd' && char2 == 'r') {
break;
}
}
if (char1 == 'd') {
break;
}
}
}
private void setupCase2(String fileName) throws IOException {
for (char char1 = 'a'; char1 <= 'z'; char1++) {
for (char char2 = 'a'; char2 <= 'z'; char2++) {
File file = new File(fileName + ".zim" + char1 + char2);
file.createNewFile();
if (char1 == 'd' && char2 == 'r') {
break;
}
}
if (char1 == 'd') {
break;
}
}
File t = new File(fileName + ".zimcp.part");
}
@After
public void RemoveTestDirectory() {
for(File child : testDir.listFiles()) {
child.delete();
}
testDir.delete();
}
}

View File

@ -0,0 +1,65 @@
/*
* Kiwix Android
* Copyright (C) 2018 Kiwix <android.kiwix.org>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.kiwix.kiwixmobile.data.local;
import com.yahoo.squidb.data.AbstractModel;
import com.yahoo.squidb.data.SquidCursor;
import com.yahoo.squidb.sql.Query;
import org.junit.Before;
import org.junit.Test;
import org.kiwix.kiwixmobile.data.ZimContentProvider;
import org.kiwix.kiwixmobile.data.local.dao.RecentSearchDao;
import org.kiwix.kiwixmobile.data.local.entity.RecentSearch;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
public class RecentSearchDatabaseTest {
@Mock private KiwixDatabase kiwixDatabase;
private RecentSearchDao recentSearchDao;
private boolean mockInitialized = false;
@Mock private SquidCursor<AbstractModel> mockedCursor;
@Before
public void executeBefore() {
if (!mockInitialized) {
MockitoAnnotations.initMocks(this);
mockInitialized = true;
}
when(kiwixDatabase.query(any(), any())).thenReturn(mockedCursor);
recentSearchDao = new RecentSearchDao(kiwixDatabase);
}
// verify the correct database query was called
@Test
public void testGetRecentSearches() {
recentSearchDao.getRecentSearches();
// verify ordering is in descending order of search ID and the results are limited to 5 only
verify(kiwixDatabase).query(any(), eq(Query.selectDistinct(RecentSearch.SEARCH_STRING).where(RecentSearch.ZIM_I_D.eq(
ZimContentProvider.getId()))
.orderBy(RecentSearch.ID.desc())
.limit(5)));
}
}

View File

@ -36,7 +36,7 @@ import javax.inject.Inject;
*/
public class BookDao {
private KiwixDatabase mDb;
public KiwixDatabase mDb;
@Inject
public BookDao(KiwixDatabase kiwixDatabase) {
@ -87,16 +87,25 @@ public class BookDao {
while (bookCursor.moveToNext()) {
Book book = new Book();
setBookDetails(book, bookCursor);
books.add(book);
}
bookCursor.close();
ArrayList<Book> FinalList = filterBookResults(books);
return FinalList;
}
public ArrayList<Book> filterBookResults(ArrayList<Book> books) {
ArrayList<Book> filteredBookList = new ArrayList<>();
for (Book book : books){
if (!FileUtils.hasPart(book.file)) {
if (book.file.exists()) {
books.add(book);
filteredBookList.add(book);
} else {
mDb.deleteWhere(BookDatabaseEntity.class, BookDatabaseEntity.URL.eq(book.file.getPath()));
}
}
}
bookCursor.close();
return books;
return filteredBookList;
}
public ArrayList<Book> getDownloadingBooks() {