Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/stefan-niedermann/nextcloud-deck.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNiedermann IT-Dienstleistungen <stefan-niedermann@users.noreply.github.com>2021-01-03 22:20:10 +0300
committerGitHub <noreply@github.com>2021-01-03 22:20:10 +0300
commita6d553786c9666b6bcbdb534b121a261e3617cb1 (patch)
treeb91248cb8c5370fec6cd7a9683b6b8bb157790a2 /app/src/test/java/it/niedermann/nextcloud/deck
parent73e5bcfabf65b4745b1e3473e46404ef14fe1a40 (diff)
Migrate instrumented tests to robolectric tests (#784)
Diffstat (limited to 'app/src/test/java/it/niedermann/nextcloud/deck')
-rw-r--r--app/src/test/java/it/niedermann/nextcloud/deck/persistence/sync/adapters/db/DataBaseAdapterTest.java88
-rw-r--r--app/src/test/java/it/niedermann/nextcloud/deck/persistence/sync/adapters/db/DeckDatabaseTestUtil.java114
-rw-r--r--app/src/test/java/it/niedermann/nextcloud/deck/persistence/sync/adapters/db/dao/AbstractDaoTest.java39
-rw-r--r--app/src/test/java/it/niedermann/nextcloud/deck/persistence/sync/adapters/db/dao/AccountDaoTest.java95
-rw-r--r--app/src/test/java/it/niedermann/nextcloud/deck/persistence/sync/adapters/db/dao/BoardDaoTest.java178
-rw-r--r--app/src/test/java/it/niedermann/nextcloud/deck/persistence/sync/adapters/db/dao/CardDaoTest.java157
-rw-r--r--app/src/test/java/it/niedermann/nextcloud/deck/persistence/sync/adapters/db/dao/StackDaoTest.java47
-rw-r--r--app/src/test/java/it/niedermann/nextcloud/deck/persistence/sync/adapters/db/dao/UserDaoTest.java35
-rw-r--r--app/src/test/java/it/niedermann/nextcloud/deck/util/AttachmentUtilTest.java53
-rw-r--r--app/src/test/java/it/niedermann/nextcloud/deck/util/DateUtilTest.java40
-rw-r--r--app/src/test/java/it/niedermann/nextcloud/deck/util/DeckColorUtilTest.java52
-rw-r--r--app/src/test/java/it/niedermann/nextcloud/deck/util/SpannableUtilTest.java55
12 files changed, 953 insertions, 0 deletions
diff --git a/app/src/test/java/it/niedermann/nextcloud/deck/persistence/sync/adapters/db/DataBaseAdapterTest.java b/app/src/test/java/it/niedermann/nextcloud/deck/persistence/sync/adapters/db/DataBaseAdapterTest.java
new file mode 100644
index 000000000..9d41c06d1
--- /dev/null
+++ b/app/src/test/java/it/niedermann/nextcloud/deck/persistence/sync/adapters/db/DataBaseAdapterTest.java
@@ -0,0 +1,88 @@
+package it.niedermann.nextcloud.deck.persistence.sync.adapters.db;
+
+import android.content.Context;
+import android.os.Build;
+
+import androidx.room.Room;
+import androidx.test.core.app.ApplicationProvider;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.annotation.Config;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.util.ArrayList;
+import java.util.List;
+
+import it.niedermann.nextcloud.deck.model.Account;
+import it.niedermann.nextcloud.deck.model.Board;
+import it.niedermann.nextcloud.deck.model.User;
+import it.niedermann.nextcloud.deck.model.full.FullBoard;
+import it.niedermann.nextcloud.deck.model.interfaces.AbstractRemoteEntity;
+
+import static it.niedermann.nextcloud.deck.persistence.sync.adapters.db.DeckDatabaseTestUtil.createAccount;
+import static it.niedermann.nextcloud.deck.persistence.sync.adapters.db.DeckDatabaseTestUtil.createBoard;
+import static it.niedermann.nextcloud.deck.persistence.sync.adapters.db.DeckDatabaseTestUtil.createUser;
+import static org.junit.Assert.assertEquals;
+
+@RunWith(RobolectricTestRunner.class)
+@Config(sdk = {Build.VERSION_CODES.P})
+public class DataBaseAdapterTest {
+
+ private DeckDatabase db;
+ private DataBaseAdapter adapter;
+
+ @Before
+ public void createAdapter() throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
+ final Constructor<DataBaseAdapter> constructor = DataBaseAdapter.class.getDeclaredConstructor(Context.class, DeckDatabase.class);
+ if (Modifier.isPrivate(constructor.getModifiers())) {
+ constructor.setAccessible(true);
+ db = Room
+ .inMemoryDatabaseBuilder(ApplicationProvider.getApplicationContext(), DeckDatabase.class)
+ .allowMainThreadQueries()
+ .build();
+ adapter = constructor.newInstance(ApplicationProvider.getApplicationContext(), db);
+ }
+ }
+
+ @After
+ public void closeDb() {
+ if (db != null) {
+ db.close();
+ }
+ }
+
+ @Test
+ public void testCreate() {
+ final Account account = createAccount(db.getAccountDao());
+ final User user = createUser(db.getUserDao(), account);
+ final Board board = createBoard(db.getBoardDao(), account, user);
+ final FullBoard fetchedBoard = adapter.getFullBoardByLocalIdDirectly(account.getId(), board.getLocalId());
+
+ assertEquals(board.getTitle(), fetchedBoard.getBoard().getTitle());
+ }
+
+ @Test
+ public void testFillSqlWithListValues() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
+ // TODO understand what the method does and write a proper test.
+ final User user = createUser(db.getUserDao(), createAccount(db.getAccountDao()));
+ final StringBuilder builder = new StringBuilder();
+ final List<Object> args = new ArrayList<>(1);
+ final List<? extends AbstractRemoteEntity> entities = new ArrayList<AbstractRemoteEntity>(1) {{
+ add(user);
+ }};
+
+ final Method fillSqlWithListValues = DataBaseAdapter.class.getDeclaredMethod("fillSqlWithListValues", StringBuilder.class, List.class, List.class);
+ fillSqlWithListValues.setAccessible(true);
+ fillSqlWithListValues.invoke(adapter, builder, args, entities);
+ assertEquals("?", builder.toString());
+ assertEquals(user.getLocalId(), args.get(0));
+ }
+
+}
diff --git a/app/src/test/java/it/niedermann/nextcloud/deck/persistence/sync/adapters/db/DeckDatabaseTestUtil.java b/app/src/test/java/it/niedermann/nextcloud/deck/persistence/sync/adapters/db/DeckDatabaseTestUtil.java
new file mode 100644
index 000000000..6583db0ff
--- /dev/null
+++ b/app/src/test/java/it/niedermann/nextcloud/deck/persistence/sync/adapters/db/DeckDatabaseTestUtil.java
@@ -0,0 +1,114 @@
+package it.niedermann.nextcloud.deck.persistence.sync.adapters.db;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.lifecycle.LiveData;
+import androidx.lifecycle.Observer;
+
+import java.util.Random;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+import it.niedermann.nextcloud.deck.model.Account;
+import it.niedermann.nextcloud.deck.model.Board;
+import it.niedermann.nextcloud.deck.model.Card;
+import it.niedermann.nextcloud.deck.model.Stack;
+import it.niedermann.nextcloud.deck.model.User;
+import it.niedermann.nextcloud.deck.persistence.sync.adapters.db.dao.AccountDao;
+import it.niedermann.nextcloud.deck.persistence.sync.adapters.db.dao.BoardDao;
+import it.niedermann.nextcloud.deck.persistence.sync.adapters.db.dao.CardDao;
+import it.niedermann.nextcloud.deck.persistence.sync.adapters.db.dao.StackDao;
+import it.niedermann.nextcloud.deck.persistence.sync.adapters.db.dao.UserDao;
+
+public class DeckDatabaseTestUtil {
+
+ private static long currentLong = 1;
+
+ private DeckDatabaseTestUtil() {
+ // Util class
+ }
+
+ /**
+ * @see <a href="https://gist.github.com/JoseAlcerreca/1e9ee05dcdd6a6a6fa1cbfc125559bba">Source</a>
+ */
+ public static <T> T getOrAwaitValue(final LiveData<T> liveData) throws InterruptedException {
+ final Object[] data = new Object[1];
+ final CountDownLatch latch = new CountDownLatch(1);
+ Observer<T> observer = new Observer<T>() {
+ @Override
+ public void onChanged(@Nullable T o) {
+ data[0] = o;
+ latch.countDown();
+ liveData.removeObserver(this);
+ }
+ };
+ liveData.observeForever(observer);
+ // Don't wait indefinitely if the LiveData is not set.
+ if (!latch.await(2, TimeUnit.SECONDS)) {
+ throw new RuntimeException("LiveData value was never set.");
+ }
+ //noinspection unchecked
+ return (T) data[0];
+ }
+
+ public static Account createAccount(@NonNull AccountDao dao) {
+ final Account accountToCreate = new Account();
+ accountToCreate.setName(randomString(15) + " " + randomString(15));
+ accountToCreate.setUserName(randomString(10));
+ accountToCreate.setUrl("https://" + randomString(10) + ".example.com");
+ final long id = dao.insert(accountToCreate);
+ return dao.getAccountByIdDirectly(id);
+ }
+
+ public static User createUser(@NonNull UserDao dao, @NonNull Account account) {
+ final User userToCreate = new User();
+ userToCreate.setDisplayname(randomString(15) + " " + randomString(15));
+ userToCreate.setUid(randomString(10));
+ userToCreate.setAccountId(account.getId());
+ final long id = dao.insert(userToCreate);
+ return dao.getUserByLocalIdDirectly(id);
+ }
+
+ public static Board createBoard(@NonNull BoardDao dao, @NonNull Account account, @NonNull User owner) {
+ final Board boardToCreate = new Board();
+ boardToCreate.setAccountId(account.getId());
+ boardToCreate.setTitle(randomString(10));
+ boardToCreate.setOwnerId(owner.getLocalId());
+ boardToCreate.setId(currentLong++);
+ long id = dao.insert(boardToCreate);
+ return dao.getBoardByIdDirectly(id);
+ }
+
+ public static Stack createStack(@NonNull StackDao dao, @NonNull Account account, @NonNull Board board) {
+ final Stack stackToCreate = new Stack();
+ stackToCreate.setTitle(randomString(5));
+ stackToCreate.setAccountId(account.getId());
+ stackToCreate.setBoardId(board.getLocalId());
+ stackToCreate.setId(currentLong++);
+ long id = dao.insert(stackToCreate);
+ return dao.getStackByLocalIdDirectly(id);
+ }
+
+ public static Card createCard(@NonNull CardDao dao, @NonNull Account account, @NonNull Stack stack) {
+ final Card cardToCreate = new Card();
+ cardToCreate.setAccountId(account.getId());
+ cardToCreate.setTitle(randomString(15));
+ cardToCreate.setDescription(randomString(50));
+ cardToCreate.setStackId(stack.getLocalId());
+ cardToCreate.setId(currentLong++);
+
+ long id = dao.insert(cardToCreate);
+ return dao.getCardByLocalIdDirectly(account.getId(), id);
+ }
+
+ private static String randomString(int length) {
+ final int leftLimit = 48; // numeral '0'
+ final int rightLimit = 122; // letter 'z'
+
+ return new Random().ints(leftLimit, rightLimit + 1)
+ .filter(i -> (i <= 57 || i >= 65) && (i <= 90 || i >= 97))
+ .limit(length)
+ .collect(StringBuilder::new, StringBuilder::appendCodePoint, StringBuilder::append)
+ .toString();
+ }
+}
diff --git a/app/src/test/java/it/niedermann/nextcloud/deck/persistence/sync/adapters/db/dao/AbstractDaoTest.java b/app/src/test/java/it/niedermann/nextcloud/deck/persistence/sync/adapters/db/dao/AbstractDaoTest.java
new file mode 100644
index 000000000..566791669
--- /dev/null
+++ b/app/src/test/java/it/niedermann/nextcloud/deck/persistence/sync/adapters/db/dao/AbstractDaoTest.java
@@ -0,0 +1,39 @@
+package it.niedermann.nextcloud.deck.persistence.sync.adapters.db.dao;
+
+import android.os.Build;
+
+import androidx.arch.core.executor.testing.InstantTaskExecutorRule;
+import androidx.room.Room;
+import androidx.test.core.app.ApplicationProvider;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.runner.RunWith;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.annotation.Config;
+
+import it.niedermann.nextcloud.deck.persistence.sync.adapters.db.DeckDatabase;
+
+@RunWith(RobolectricTestRunner.class)
+@Config(sdk = {Build.VERSION_CODES.P})
+public abstract class AbstractDaoTest {
+
+ @Rule
+ public InstantTaskExecutorRule instantTaskExecutorRule = new InstantTaskExecutorRule();
+
+ protected DeckDatabase db;
+
+ @Before
+ public void createDb() {
+ db = Room
+ .inMemoryDatabaseBuilder(ApplicationProvider.getApplicationContext(), DeckDatabase.class)
+ .allowMainThreadQueries()
+ .build();
+ }
+
+ @After
+ public void closeDb() {
+ db.close();
+ }
+}
diff --git a/app/src/test/java/it/niedermann/nextcloud/deck/persistence/sync/adapters/db/dao/AccountDaoTest.java b/app/src/test/java/it/niedermann/nextcloud/deck/persistence/sync/adapters/db/dao/AccountDaoTest.java
new file mode 100644
index 000000000..889537c71
--- /dev/null
+++ b/app/src/test/java/it/niedermann/nextcloud/deck/persistence/sync/adapters/db/dao/AccountDaoTest.java
@@ -0,0 +1,95 @@
+package it.niedermann.nextcloud.deck.persistence.sync.adapters.db.dao;
+
+import android.os.Build;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.annotation.Config;
+
+import it.niedermann.nextcloud.deck.model.Account;
+import it.niedermann.nextcloud.deck.persistence.sync.adapters.db.DeckDatabaseTestUtil;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNull;
+
+@RunWith(RobolectricTestRunner.class)
+@Config(sdk = {Build.VERSION_CODES.P})
+public class AccountDaoTest extends AbstractDaoTest {
+
+ @Test
+ public void testCreate() {
+ final Account accountToCreate = new Account();
+ accountToCreate.setName("test@example.com");
+ accountToCreate.setUserName("test");
+ accountToCreate.setUrl("https://example.com");
+
+ long id = db.getAccountDao().insert(accountToCreate);
+ final Account account = db.getAccountDao().getAccountByIdDirectly(id);
+
+ assertEquals("test", account.getUserName());
+ assertEquals("https://example.com", account.getUrl());
+ assertEquals(Integer.valueOf(0), account.getColor());
+ assertEquals(Integer.valueOf(0), account.getTextColor());
+ assertEquals("0.6.4", account.getServerDeckVersion());
+ assertEquals("https://example.com/index.php/avatar/test/1337", account.getAvatarUrl(1337));
+ assertEquals(1, db.getAccountDao().countAccountsDirectly());
+ assertNull(account.getEtag());
+ assertFalse(account.isMaintenanceEnabled());
+ }
+
+ @Test
+ public void testGetAccountById() throws InterruptedException {
+ final Account account = DeckDatabaseTestUtil.createAccount(db.getAccountDao());
+ assertEquals(account.getName(), DeckDatabaseTestUtil.getOrAwaitValue(db.getAccountDao().getAccountById(account.getId())).getName());
+ }
+
+ @Test
+ public void testGetAccountByName() throws InterruptedException {
+ final Account account = DeckDatabaseTestUtil.createAccount(db.getAccountDao());
+ assertEquals(account.getUserName(), DeckDatabaseTestUtil.getOrAwaitValue(db.getAccountDao().getAccountByName(account.getName())).getUserName());
+ }
+
+ @Test
+ public void testGetAllAccounts() throws InterruptedException {
+ final int expectedCount = 13;
+ for (int i = 0; i < expectedCount; i++) {
+ DeckDatabaseTestUtil.createAccount(db.getAccountDao());
+ }
+ assertEquals(expectedCount, DeckDatabaseTestUtil.getOrAwaitValue(db.getAccountDao().getAllAccounts()).size());
+ }
+
+ @Test
+ public void testCountAccountsDirectly() {
+ final int expectedCount = 12;
+ for (int i = 0; i < expectedCount; i++) {
+ DeckDatabaseTestUtil.createAccount(db.getAccountDao());
+ }
+ assertEquals(expectedCount, db.getAccountDao().countAccountsDirectly());
+ }
+
+ @Test
+ public void testCountAccounts() throws InterruptedException {
+ final int expectedCount = 13;
+ for (int i = 0; i < expectedCount; i++) {
+ DeckDatabaseTestUtil.createAccount(db.getAccountDao());
+ }
+ assertEquals(Integer.valueOf(expectedCount), DeckDatabaseTestUtil.getOrAwaitValue(db.getAccountDao().countAccounts()));
+ }
+
+ @Test
+ public void testGetAllAccountsDirectly() {
+ final int expectedCount = 12;
+ for (int i = 0; i < expectedCount; i++) {
+ DeckDatabaseTestUtil.createAccount(db.getAccountDao());
+ }
+ assertEquals(expectedCount, db.getAccountDao().getAllAccountsDirectly().size());
+ }
+
+ @Test
+ public void testGetAccountByNameDirectly() {
+ final Account account = DeckDatabaseTestUtil.createAccount(db.getAccountDao());
+ assertEquals(account.getName(), db.getAccountDao().getAccountByNameDirectly(account.getName()).getName());
+ }
+}
diff --git a/app/src/test/java/it/niedermann/nextcloud/deck/persistence/sync/adapters/db/dao/BoardDaoTest.java b/app/src/test/java/it/niedermann/nextcloud/deck/persistence/sync/adapters/db/dao/BoardDaoTest.java
new file mode 100644
index 000000000..6b5408668
--- /dev/null
+++ b/app/src/test/java/it/niedermann/nextcloud/deck/persistence/sync/adapters/db/dao/BoardDaoTest.java
@@ -0,0 +1,178 @@
+package it.niedermann.nextcloud.deck.persistence.sync.adapters.db.dao;
+
+import android.os.Build;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.annotation.Config;
+
+import java.time.Instant;
+import java.util.List;
+
+import it.niedermann.nextcloud.deck.model.Account;
+import it.niedermann.nextcloud.deck.model.Board;
+import it.niedermann.nextcloud.deck.model.Card;
+import it.niedermann.nextcloud.deck.model.Stack;
+import it.niedermann.nextcloud.deck.model.User;
+import it.niedermann.nextcloud.deck.model.enums.DBStatus;
+import it.niedermann.nextcloud.deck.persistence.sync.adapters.db.DeckDatabaseTestUtil;
+
+import static it.niedermann.nextcloud.deck.persistence.sync.adapters.db.DeckDatabaseTestUtil.createAccount;
+import static it.niedermann.nextcloud.deck.persistence.sync.adapters.db.DeckDatabaseTestUtil.createBoard;
+import static it.niedermann.nextcloud.deck.persistence.sync.adapters.db.DeckDatabaseTestUtil.createCard;
+import static it.niedermann.nextcloud.deck.persistence.sync.adapters.db.DeckDatabaseTestUtil.createStack;
+import static it.niedermann.nextcloud.deck.persistence.sync.adapters.db.DeckDatabaseTestUtil.createUser;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+@RunWith(RobolectricTestRunner.class)
+@Config(sdk = {Build.VERSION_CODES.P})
+public class BoardDaoTest extends AbstractDaoTest {
+
+ @Test
+ public void writeAndReadBoard() {
+ final Account account = createAccount(db.getAccountDao());
+ final User user = DeckDatabaseTestUtil.createUser(db.getUserDao(), account);
+
+ final Board boardToCreate = new Board();
+ boardToCreate.setAccountId(account.getId());
+ boardToCreate.setTitle("Test-Board");
+ boardToCreate.setOwnerId(user.getLocalId());
+ boardToCreate.setId(1337L);
+
+ long id = db.getBoardDao().insert(boardToCreate);
+ final Board board = db.getBoardDao().getBoardByIdDirectly(id);
+
+ assertEquals("Test-Board", board.getTitle());
+ assertEquals(board, db.getBoardDao().getBoardByRemoteIdDirectly(account.getId(), board.getId()));
+ assertEquals(board, db.getBoardDao().getBoardForAccountByNameDirectly(account.getId(), "Test-Board"));
+ assertEquals(board, db.getBoardDao().getFullBoardByLocalIdDirectly(account.getId(), board.getLocalId()).getBoard());
+ assertEquals(board, db.getBoardDao().getFullBoardByRemoteIdDirectly(account.getId(), board.getId()).getBoard());
+ }
+
+ @Test
+ public void testGetBoardsForAccount() throws InterruptedException {
+ final Account account = createAccount(db.getAccountDao());
+ final User owner = createUser(db.getUserDao(), account);
+ final Board boardVisible1 = createBoard(db.getBoardDao(), account, owner);
+ final Board boardVisible2 = createBoard(db.getBoardDao(), account, owner);
+ final Board boardVisible3 = createBoard(db.getBoardDao(), account, owner);
+ final Board boardInVisible1 = createBoard(db.getBoardDao(), account, owner);
+ boardInVisible1.setDeletedAt(Instant.now());
+ final Board boardInVisible2 = createBoard(db.getBoardDao(), account, owner);
+ boardInVisible2.setStatus(3);
+ final Board boardInVisible3 = createBoard(db.getBoardDao(), account, owner);
+ boardInVisible3.setStatusEnum(DBStatus.LOCAL_DELETED);
+ final Board boardVisibleArchived = createBoard(db.getBoardDao(), account, owner);
+ boardVisibleArchived.setArchived(true);
+ db.getBoardDao().update(boardInVisible1, boardInVisible2, boardInVisible3, boardVisibleArchived);
+
+ final List<Board> boards = DeckDatabaseTestUtil.getOrAwaitValue(db.getBoardDao().getBoardsForAccount(account.getId()));
+ assertEquals(4, boards.size());
+ assertTrue(boards.stream().anyMatch((board -> boardVisible1.getLocalId().equals(board.getLocalId()))));
+ assertTrue(boards.stream().anyMatch((board -> boardVisible2.getLocalId().equals(board.getLocalId()))));
+ assertTrue(boards.stream().anyMatch((board -> boardVisible3.getLocalId().equals(board.getLocalId()))));
+ assertTrue(boards.stream().anyMatch((board -> boardVisibleArchived.getLocalId().equals(board.getLocalId()))));
+ assertFalse(boards.stream().anyMatch((board -> boardInVisible1.getLocalId().equals(board.getLocalId()))));
+ assertFalse(boards.stream().anyMatch((board -> boardInVisible2.getLocalId().equals(board.getLocalId()))));
+ assertFalse(boards.stream().anyMatch((board -> boardInVisible3.getLocalId().equals(board.getLocalId()))));
+ }
+
+ @Test
+ public void testGetArchivedBoardsForAccount() throws InterruptedException {
+ final Account account = createAccount(db.getAccountDao());
+ final User owner = createUser(db.getUserDao(), account);
+ final Board board1 = createBoard(db.getBoardDao(), account, owner);
+ final Board board2 = createBoard(db.getBoardDao(), account, owner);
+ final Board board3 = createBoard(db.getBoardDao(), account, owner);
+ final Board board5 = createBoard(db.getBoardDao(), account, owner);
+ board5.setDeletedAt(Instant.now());
+ board5.setArchived(true);
+ final Board board6 = createBoard(db.getBoardDao(), account, owner);
+ board6.setStatus(3);
+ board6.setArchived(true);
+ final Board board7 = createBoard(db.getBoardDao(), account, owner);
+ board7.setStatusEnum(DBStatus.LOCAL_DELETED);
+ board7.setArchived(true);
+ final Board board4 = createBoard(db.getBoardDao(), account, owner);
+ board4.setArchived(true);
+ db.getBoardDao().update(board5, board6, board7, board4);
+
+ final List<Board> boards = DeckDatabaseTestUtil.getOrAwaitValue(db.getBoardDao().getArchivedBoardsForAccount(account.getId()));
+ assertEquals(1, boards.size());
+ assertFalse(boards.stream().anyMatch((board -> board1.getLocalId().equals(board.getLocalId()))));
+ assertFalse(boards.stream().anyMatch((board -> board2.getLocalId().equals(board.getLocalId()))));
+ assertFalse(boards.stream().anyMatch((board -> board3.getLocalId().equals(board.getLocalId()))));
+ assertTrue(boards.stream().anyMatch((board -> board4.getLocalId().equals(board.getLocalId()))));
+ assertFalse(boards.stream().anyMatch((board -> board5.getLocalId().equals(board.getLocalId()))));
+ assertFalse(boards.stream().anyMatch((board -> board6.getLocalId().equals(board.getLocalId()))));
+ assertFalse(boards.stream().anyMatch((board -> board7.getLocalId().equals(board.getLocalId()))));
+ }
+
+ @Test
+ public void testGetNonArchivedBoardsForAccount() throws InterruptedException {
+ final Account account = createAccount(db.getAccountDao());
+ final User owner = createUser(db.getUserDao(), account);
+ final Board board1 = createBoard(db.getBoardDao(), account, owner);
+ final Board board2 = createBoard(db.getBoardDao(), account, owner);
+ final Board board3 = createBoard(db.getBoardDao(), account, owner);
+ final Board board5 = createBoard(db.getBoardDao(), account, owner);
+ board5.setDeletedAt(Instant.now());
+ board5.setArchived(true);
+ final Board board6 = createBoard(db.getBoardDao(), account, owner);
+ board6.setStatus(3);
+ board6.setArchived(true);
+ final Board board7 = createBoard(db.getBoardDao(), account, owner);
+ board7.setStatusEnum(DBStatus.LOCAL_DELETED);
+ board7.setArchived(true);
+ final Board board4 = createBoard(db.getBoardDao(), account, owner);
+ board4.setArchived(true);
+ db.getBoardDao().update(board5, board6, board7, board4);
+
+ final List<Board> boards = DeckDatabaseTestUtil.getOrAwaitValue(db.getBoardDao().getNonArchivedBoardsForAccount(account.getId()));
+ assertEquals(3, boards.size());
+ assertTrue(boards.stream().anyMatch((board -> board1.getLocalId().equals(board.getLocalId()))));
+ assertTrue(boards.stream().anyMatch((board -> board2.getLocalId().equals(board.getLocalId()))));
+ assertTrue(boards.stream().anyMatch((board -> board3.getLocalId().equals(board.getLocalId()))));
+ assertFalse(boards.stream().anyMatch((board -> board4.getLocalId().equals(board.getLocalId()))));
+ assertFalse(boards.stream().anyMatch((board -> board5.getLocalId().equals(board.getLocalId()))));
+ assertFalse(boards.stream().anyMatch((board -> board6.getLocalId().equals(board.getLocalId()))));
+ assertFalse(boards.stream().anyMatch((board -> board7.getLocalId().equals(board.getLocalId()))));
+ }
+
+ @Test
+ public void testGetLocalBoardIdByCardRemoteIdAndAccountId() throws InterruptedException {
+ final Account account = createAccount(db.getAccountDao());
+ final User owner = createUser(db.getUserDao(), account);
+ final Board board = createBoard(db.getBoardDao(), account, owner);
+ final Stack stack = createStack(db.getStackDao(), account, board);
+ final Card card = createCard(db.getCardDao(), account, stack);
+
+ assertEquals(board.getLocalId(), DeckDatabaseTestUtil.getOrAwaitValue(db.getBoardDao().getLocalBoardIdByCardRemoteIdAndAccountId(card.getId(), account.getId())));
+ }
+
+ @Test
+ public void testCountArchivedBoards() throws InterruptedException {
+ final Account account = createAccount(db.getAccountDao());
+ final User owner = createUser(db.getUserDao(), account);
+ final Board board1 = createBoard(db.getBoardDao(), account, owner);
+ final Board board2 = createBoard(db.getBoardDao(), account, owner);
+ final Board board3 = createBoard(db.getBoardDao(), account, owner);
+ final Board board5 = createBoard(db.getBoardDao(), account, owner);
+ board5.setDeletedAt(Instant.now());
+ board5.setArchived(true);
+ final Board board6 = createBoard(db.getBoardDao(), account, owner);
+ board6.setStatus(3);
+ board6.setArchived(true);
+ final Board board7 = createBoard(db.getBoardDao(), account, owner);
+ board7.setStatusEnum(DBStatus.LOCAL_DELETED);
+ board7.setArchived(true);
+ final Board board4 = createBoard(db.getBoardDao(), account, owner);
+ board4.setArchived(true);
+ db.getBoardDao().update(board5, board6, board7, board4);
+
+ assertEquals(Integer.valueOf(1), DeckDatabaseTestUtil.getOrAwaitValue(db.getBoardDao().countArchivedBoards(account.getId())));
+ }
+}
diff --git a/app/src/test/java/it/niedermann/nextcloud/deck/persistence/sync/adapters/db/dao/CardDaoTest.java b/app/src/test/java/it/niedermann/nextcloud/deck/persistence/sync/adapters/db/dao/CardDaoTest.java
new file mode 100644
index 000000000..a3401de42
--- /dev/null
+++ b/app/src/test/java/it/niedermann/nextcloud/deck/persistence/sync/adapters/db/dao/CardDaoTest.java
@@ -0,0 +1,157 @@
+package it.niedermann.nextcloud.deck.persistence.sync.adapters.db.dao;
+
+import android.os.Build;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.annotation.Config;
+
+import java.util.List;
+
+import it.niedermann.nextcloud.deck.model.Account;
+import it.niedermann.nextcloud.deck.model.Board;
+import it.niedermann.nextcloud.deck.model.Card;
+import it.niedermann.nextcloud.deck.model.Stack;
+import it.niedermann.nextcloud.deck.model.User;
+import it.niedermann.nextcloud.deck.model.enums.DBStatus;
+import it.niedermann.nextcloud.deck.model.full.FullCard;
+import it.niedermann.nextcloud.deck.persistence.sync.adapters.db.DeckDatabaseTestUtil;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+@RunWith(RobolectricTestRunner.class)
+@Config(sdk = {Build.VERSION_CODES.P})
+public class CardDaoTest extends AbstractDaoTest {
+
+ private Account account;
+ private User user;
+ private Board board;
+
+ @Before
+ public void setupAccount() {
+ account = DeckDatabaseTestUtil.createAccount(db.getAccountDao());
+ user = DeckDatabaseTestUtil.createUser(db.getUserDao(), account);
+ board = DeckDatabaseTestUtil.createBoard(db.getBoardDao(), account, user);
+ }
+
+ @Test
+ public void writeAndReadCard() {
+ final Stack stack = DeckDatabaseTestUtil.createStack(db.getStackDao(), account, board);
+
+ final Card cardToCreate = new Card();
+ cardToCreate.setAccountId(account.getId());
+ cardToCreate.setTitle("Test-Card");
+ cardToCreate.setDescription("Holy Moly Description");
+ cardToCreate.setStackId(stack.getLocalId());
+ cardToCreate.setId(1234L);
+
+ long id = db.getCardDao().insert(cardToCreate);
+ final Card card = db.getCardDao().getCardByLocalIdDirectly(account.getId(), id);
+
+ assertEquals("Test-Card", card.getTitle());
+ assertEquals(card, db.getCardDao().getCardByRemoteIdDirectly(account.getId(), card.getId()));
+ assertEquals(card, db.getCardDao().getFullCardByLocalIdDirectly(account.getId(), card.getLocalId()).getCard());
+ assertEquals(card, db.getCardDao().getFullCardByRemoteIdDirectly(account.getId(), card.getId()).getCard());
+
+ card.setTitle("Changed Title");
+
+ db.getCardDao().update(card);
+
+ assertEquals("Changed Title", db.getCardDao().getCardByLocalIdDirectly(account.getId(), id).getTitle());
+ }
+
+ @Test
+ public void testGetLocallyChangedCards() {
+ final Stack stack1 = DeckDatabaseTestUtil.createStack(db.getStackDao(), account, board);
+ final Stack stack2 = DeckDatabaseTestUtil.createStack(db.getStackDao(), account, board);
+ final Card card1 = DeckDatabaseTestUtil.createCard(db.getCardDao(), account, stack1);
+ final Card card2 = DeckDatabaseTestUtil.createCard(db.getCardDao(), account, stack1);
+ final Card card3 = DeckDatabaseTestUtil.createCard(db.getCardDao(), account, stack2);
+ final Card card4 = DeckDatabaseTestUtil.createCard(db.getCardDao(), account, stack2);
+ final Card card5 = DeckDatabaseTestUtil.createCard(db.getCardDao(), account, stack2);
+
+ card1.setStatusEnum(DBStatus.LOCAL_EDITED);
+ card2.setStatusEnum(DBStatus.LOCAL_MOVED);
+ card3.setStatusEnum(DBStatus.LOCAL_EDITED_SILENT);
+ card4.setStatusEnum(DBStatus.LOCAL_DELETED);
+ card5.setStatusEnum(DBStatus.UP_TO_DATE);
+ db.getCardDao().update(card1, card2, card3, card4, card5);
+
+ final List<FullCard> locallyChangedCards = db.getCardDao().getLocallyChangedCardsDirectly(account.getId());
+ assertEquals(4, locallyChangedCards.size());
+ assertTrue(locallyChangedCards.stream().anyMatch((fullCard -> fullCard.getCard().equals(card1))));
+ assertTrue(locallyChangedCards.stream().anyMatch((fullCard -> fullCard.getCard().equals(card2))));
+ assertTrue(locallyChangedCards.stream().anyMatch((fullCard -> fullCard.getCard().equals(card3))));
+ assertTrue(locallyChangedCards.stream().anyMatch((fullCard -> fullCard.getCard().equals(card4))));
+ assertFalse(locallyChangedCards.stream().anyMatch((fullCard -> fullCard.getCard().equals(card5))));
+
+ final List<FullCard> locallyChangedCardsOfStack1 = db.getCardDao().getLocallyChangedCardsByLocalStackIdDirectly(account.getId(), stack1.getLocalId());
+ assertEquals(2, locallyChangedCardsOfStack1.size());
+ assertTrue(locallyChangedCardsOfStack1.stream().anyMatch((fullCard -> fullCard.getCard().equals(card1))));
+ assertTrue(locallyChangedCardsOfStack1.stream().anyMatch((fullCard -> fullCard.getCard().equals(card2))));
+ assertFalse(locallyChangedCardsOfStack1.stream().anyMatch((fullCard -> fullCard.getCard().equals(card3))));
+ assertFalse(locallyChangedCardsOfStack1.stream().anyMatch((fullCard -> fullCard.getCard().equals(card4))));
+ assertFalse(locallyChangedCardsOfStack1.stream().anyMatch((fullCard -> fullCard.getCard().equals(card5))));
+
+ final List<FullCard> locallyChangedCardsOfStack2 = db.getCardDao().getLocallyChangedCardsByLocalStackIdDirectly(account.getId(), stack2.getLocalId());
+ assertEquals(2, locallyChangedCardsOfStack2.size());
+ assertFalse(locallyChangedCardsOfStack2.stream().anyMatch((fullCard -> fullCard.getCard().equals(card1))));
+ assertFalse(locallyChangedCardsOfStack2.stream().anyMatch((fullCard -> fullCard.getCard().equals(card2))));
+ assertTrue(locallyChangedCardsOfStack2.stream().anyMatch((fullCard -> fullCard.getCard().equals(card3))));
+ assertTrue(locallyChangedCardsOfStack2.stream().anyMatch((fullCard -> fullCard.getCard().equals(card4))));
+ assertFalse(locallyChangedCardsOfStack2.stream().anyMatch((fullCard -> fullCard.getCard().equals(card5))));
+ }
+
+ @Test
+ public void testGetFullCardsForStackDirectly() {
+ final Stack stack1 = DeckDatabaseTestUtil.createStack(db.getStackDao(), account, board);
+ final Stack stack2 = DeckDatabaseTestUtil.createStack(db.getStackDao(), account, board);
+ final Card card1 = DeckDatabaseTestUtil.createCard(db.getCardDao(), account, stack1);
+ final Card card2 = DeckDatabaseTestUtil.createCard(db.getCardDao(), account, stack1);
+ final Card card3 = DeckDatabaseTestUtil.createCard(db.getCardDao(), account, stack2);
+ final Card card4 = DeckDatabaseTestUtil.createCard(db.getCardDao(), account, stack2);
+ final Card card5 = DeckDatabaseTestUtil.createCard(db.getCardDao(), account, stack2);
+
+ final List<FullCard> locallyChangedCardsOfStack1 = db.getCardDao().getFullCardsForStackDirectly(account.getId(), stack1.getLocalId());
+ assertEquals(2, locallyChangedCardsOfStack1.size());
+ assertTrue(locallyChangedCardsOfStack1.stream().anyMatch((fullCard -> fullCard.getCard().equals(card1))));
+ assertTrue(locallyChangedCardsOfStack1.stream().anyMatch((fullCard -> fullCard.getCard().equals(card2))));
+ assertFalse(locallyChangedCardsOfStack1.stream().anyMatch((fullCard -> fullCard.getCard().equals(card3))));
+ assertFalse(locallyChangedCardsOfStack1.stream().anyMatch((fullCard -> fullCard.getCard().equals(card4))));
+ assertFalse(locallyChangedCardsOfStack1.stream().anyMatch((fullCard -> fullCard.getCard().equals(card5))));
+
+ final List<FullCard> locallyChangedCardsOfStack2 = db.getCardDao().getFullCardsForStackDirectly(account.getId(), stack2.getLocalId());
+ assertEquals(3, locallyChangedCardsOfStack2.size());
+ assertFalse(locallyChangedCardsOfStack2.stream().anyMatch((fullCard -> fullCard.getCard().equals(card1))));
+ assertFalse(locallyChangedCardsOfStack2.stream().anyMatch((fullCard -> fullCard.getCard().equals(card2))));
+ assertTrue(locallyChangedCardsOfStack2.stream().anyMatch((fullCard -> fullCard.getCard().equals(card3))));
+ assertTrue(locallyChangedCardsOfStack2.stream().anyMatch((fullCard -> fullCard.getCard().equals(card4))));
+ assertTrue(locallyChangedCardsOfStack2.stream().anyMatch((fullCard -> fullCard.getCard().equals(card5))));
+ }
+
+ @Test
+ public void testGetHighestStackOrder() {
+ final Stack stack = DeckDatabaseTestUtil.createStack(db.getStackDao(), account, board);
+ final Card card1 = DeckDatabaseTestUtil.createCard(db.getCardDao(), account, stack);
+ final Card card2 = DeckDatabaseTestUtil.createCard(db.getCardDao(), account, stack);
+ final Card card3 = DeckDatabaseTestUtil.createCard(db.getCardDao(), account, stack);
+ final Card card4 = DeckDatabaseTestUtil.createCard(db.getCardDao(), account, stack);
+ card1.setOrder(20);
+ card2.setOrder(10);
+ card3.setOrder(50);
+ card4.setOrder(40);
+ db.getCardDao().update(card1, card2, card3, card4);
+ assertEquals(Integer.valueOf(50), db.getCardDao().getHighestOrderInStack(stack.getLocalId()));
+ }
+
+ @Test
+ public void testGetLocalStackIdByLocalCardId() {
+ final Stack stack = DeckDatabaseTestUtil.createStack(db.getStackDao(), account, board);
+ final Card card = DeckDatabaseTestUtil.createCard(db.getCardDao(), account, stack);
+ assertEquals(stack.getLocalId(), card.getLocalId());
+ }
+}
diff --git a/app/src/test/java/it/niedermann/nextcloud/deck/persistence/sync/adapters/db/dao/StackDaoTest.java b/app/src/test/java/it/niedermann/nextcloud/deck/persistence/sync/adapters/db/dao/StackDaoTest.java
new file mode 100644
index 000000000..6bc5d32b7
--- /dev/null
+++ b/app/src/test/java/it/niedermann/nextcloud/deck/persistence/sync/adapters/db/dao/StackDaoTest.java
@@ -0,0 +1,47 @@
+package it.niedermann.nextcloud.deck.persistence.sync.adapters.db.dao;
+
+import android.os.Build;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.annotation.Config;
+
+import java.util.List;
+
+import it.niedermann.nextcloud.deck.model.Account;
+import it.niedermann.nextcloud.deck.model.Board;
+import it.niedermann.nextcloud.deck.model.Stack;
+import it.niedermann.nextcloud.deck.model.User;
+import it.niedermann.nextcloud.deck.model.full.FullStack;
+import it.niedermann.nextcloud.deck.persistence.sync.adapters.db.DeckDatabaseTestUtil;
+
+import static org.junit.Assert.assertEquals;
+
+@RunWith(RobolectricTestRunner.class)
+@Config(sdk = {Build.VERSION_CODES.P})
+public class StackDaoTest extends AbstractDaoTest {
+
+ @Test
+ public void writeAndReadStack() {
+ final Account account = DeckDatabaseTestUtil.createAccount(db.getAccountDao());
+ final User user = DeckDatabaseTestUtil.createUser(db.getUserDao(), account);
+ final Board board = DeckDatabaseTestUtil.createBoard(db.getBoardDao(), account, user);
+
+ final Stack stackToCreate = new Stack();
+ stackToCreate.setAccountId(account.getId());
+ stackToCreate.setTitle("Test-Stack");
+ stackToCreate.setBoardId(board.getLocalId());
+ stackToCreate.setId(1337L);
+
+ long id = db.getStackDao().insert(stackToCreate);
+ final Stack stack = db.getStackDao().getStackByLocalIdDirectly(id);
+
+ assertEquals("Test-Stack", stack.getTitle());
+ assertEquals(stack, db.getStackDao().getFullStackByLocalIdDirectly(id).getStack());
+ assertEquals(stack, db.getStackDao().getFullStackByRemoteIdDirectly(account.getId(), board.getLocalId(), stack.getId()).getStack());
+ final List<FullStack> stacksOfBoard = db.getStackDao().getFullStacksForBoardDirectly(account.getId(), board.getLocalId());
+ assertEquals(1, stacksOfBoard.size());
+ assertEquals(stack, stacksOfBoard.get(0).getStack());
+ }
+}
diff --git a/app/src/test/java/it/niedermann/nextcloud/deck/persistence/sync/adapters/db/dao/UserDaoTest.java b/app/src/test/java/it/niedermann/nextcloud/deck/persistence/sync/adapters/db/dao/UserDaoTest.java
new file mode 100644
index 000000000..edb5d8181
--- /dev/null
+++ b/app/src/test/java/it/niedermann/nextcloud/deck/persistence/sync/adapters/db/dao/UserDaoTest.java
@@ -0,0 +1,35 @@
+package it.niedermann.nextcloud.deck.persistence.sync.adapters.db.dao;
+
+import android.os.Build;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.annotation.Config;
+
+import it.niedermann.nextcloud.deck.model.Account;
+import it.niedermann.nextcloud.deck.model.User;
+import it.niedermann.nextcloud.deck.persistence.sync.adapters.db.DeckDatabaseTestUtil;
+
+import static org.junit.Assert.assertEquals;
+
+@RunWith(RobolectricTestRunner.class)
+@Config(sdk = {Build.VERSION_CODES.P})
+public class UserDaoTest extends AbstractDaoTest {
+
+ @Test
+ public void writeAndReadUser() {
+ final Account account = DeckDatabaseTestUtil.createAccount(db.getAccountDao());
+
+ final User userToCreate = new User();
+ userToCreate.setDisplayname("Test Tester");
+ userToCreate.setUid("test");
+ userToCreate.setAccountId(account.getId());
+
+ db.getUserDao().insert(userToCreate);
+ final User user = db.getUserDao().getUserByUidDirectly(account.getId(), "test");
+
+ assertEquals("Test Tester", user.getDisplayname());
+ }
+
+}
diff --git a/app/src/test/java/it/niedermann/nextcloud/deck/util/AttachmentUtilTest.java b/app/src/test/java/it/niedermann/nextcloud/deck/util/AttachmentUtilTest.java
new file mode 100644
index 000000000..782c319c3
--- /dev/null
+++ b/app/src/test/java/it/niedermann/nextcloud/deck/util/AttachmentUtilTest.java
@@ -0,0 +1,53 @@
+package it.niedermann.nextcloud.deck.util;
+
+import android.os.Build;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.annotation.Config;
+
+import it.niedermann.nextcloud.deck.model.Attachment;
+import it.niedermann.nextcloud.deck.model.ocs.Version;
+
+import static org.junit.Assert.assertEquals;
+
+@RunWith(RobolectricTestRunner.class)
+@Config(sdk = {Build.VERSION_CODES.P})
+public class AttachmentUtilTest {
+
+ @Test
+ public void testGetThumbnailUrl() {
+ final Version versionThatDoesSupportFileAttachments = new Version("1.3.0", 1, 3, 0);
+ final Version versionThatDoesNotSupportFileAttachments = new Version("1.2.0", 1, 2, 0);
+ final String accountUrl = "https://example.com";
+
+ // TODO depends on https://github.com/nextcloud/deck/pull/2638
+// final Attachment attachment1 = new Attachment();
+// attachment1.setFileId("1337");
+// final String thumbnailUrl1 = AttachmentUtil.getThumbnailUrl(versionThatDoesSupportFileAttachments, accountUrl, -1L, attachment1, 500);
+// assertEquals("https://example.com/index.php/core/preview?fileId=1337&x=500&y=500", thumbnailUrl1);
+//
+// final Attachment attachment2 = new Attachment();
+// attachment2.setFileId("0815");
+// final String thumbnailUrl2 = AttachmentUtil.getThumbnailUrl(versionThatDoesSupportFileAttachments, accountUrl, 0L, attachment2, 4711);
+// assertEquals("https://example.com/index.php/core/preview?fileId=0815&x=4711&y=4711", thumbnailUrl2);
+
+ // Given there is an invalid fileId...
+ final Attachment attachment3 = new Attachment();
+ attachment3.setId(999L);
+ attachment3.setFileId("");
+ final String thumbnailUrl3 = AttachmentUtil.getThumbnailUrl(versionThatDoesSupportFileAttachments, accountUrl, 15L, attachment3, 205);
+ // ... a fallback to the attachment itself should be returned
+ assertEquals("https://example.com/index.php/apps/deck/cards/15/attachment/999", thumbnailUrl3);
+
+ // Given the server version does not support file attachments yet...
+ final Attachment attachment4 = new Attachment();
+ attachment4.setId(111L);
+ attachment4.setFileId("222");
+ final String thumbnailUrl4 = AttachmentUtil.getThumbnailUrl(versionThatDoesNotSupportFileAttachments, accountUrl, 333L, attachment4, 444);
+ // ... a fallback to the attachment itself should be returned
+ assertEquals("https://example.com/index.php/apps/deck/cards/333/attachment/111", thumbnailUrl4);
+ }
+
+}
diff --git a/app/src/test/java/it/niedermann/nextcloud/deck/util/DateUtilTest.java b/app/src/test/java/it/niedermann/nextcloud/deck/util/DateUtilTest.java
new file mode 100644
index 000000000..742a7a8b9
--- /dev/null
+++ b/app/src/test/java/it/niedermann/nextcloud/deck/util/DateUtilTest.java
@@ -0,0 +1,40 @@
+package it.niedermann.nextcloud.deck.util;
+
+import android.content.Context;
+import android.os.Build;
+
+import androidx.test.core.app.ApplicationProvider;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.annotation.Config;
+
+import java.time.Duration;
+import java.time.ZoneId;
+import java.time.ZonedDateTime;
+import java.util.stream.Stream;
+
+import static org.junit.Assert.assertEquals;
+
+@RunWith(RobolectricTestRunner.class)
+@Config(sdk = {Build.VERSION_CODES.P})
+public class DateUtilTest {
+
+ @Test
+ public void testGetRelativeDateTimeString() {
+ final Context appContext = ApplicationProvider.getApplicationContext();
+
+ Stream.of(10, 20, 30, 40, 50)
+ .map(secondsAgo -> ZonedDateTime.now().minus(Duration.ofSeconds(secondsAgo)).toInstant().toEpochMilli())
+ .forEach(secondsAgoInMillis -> assertEquals("Below one minute diff, it should just print \"seconds\"", "seconds ago", DateUtil.getRelativeDateTimeString(appContext, secondsAgoInMillis)));
+
+ // TODO Robolectric implementation seems to behave different from emulated device
+// Stream.of(10, 20, 30, 40, 50)
+// .forEach(minutesAgo -> assertEquals("Minutes ago should print the minutes", minutesAgo + " minutes ago", DateUtil.getRelativeDateTimeString(appContext, ZonedDateTime.now().minus(Duration.ofMinutes(minutesAgo)).toInstant().toEpochMilli())));
+
+ assertEquals("Very long time ago should print the complete date", "4/13/2018", DateUtil.getRelativeDateTimeString(appContext, ZonedDateTime.of(2018,
+ 4, 13, 10, 45, 0, 0, ZoneId.systemDefault()).toInstant().toEpochMilli()));
+ }
+
+}
diff --git a/app/src/test/java/it/niedermann/nextcloud/deck/util/DeckColorUtilTest.java b/app/src/test/java/it/niedermann/nextcloud/deck/util/DeckColorUtilTest.java
new file mode 100644
index 000000000..986ebcf52
--- /dev/null
+++ b/app/src/test/java/it/niedermann/nextcloud/deck/util/DeckColorUtilTest.java
@@ -0,0 +1,52 @@
+package it.niedermann.nextcloud.deck.util;
+
+import android.graphics.Color;
+import android.os.Build;
+
+import androidx.core.util.Pair;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.annotation.Config;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+@RunWith(RobolectricTestRunner.class)
+@Config(sdk = {Build.VERSION_CODES.P})
+public class DeckColorUtilTest {
+
+ @Test
+ public void testContrastRatioIsSufficient() {
+ final List<Pair<Integer, Integer>> sufficientContrastColorPairs = new ArrayList<>();
+ sufficientContrastColorPairs.add(new Pair<>(Color.BLACK, Color.WHITE));
+ sufficientContrastColorPairs.add(new Pair<>(Color.WHITE, Color.parseColor("#0082C9")));
+
+ for (Pair<Integer, Integer> colorPair : sufficientContrastColorPairs) {
+ assert colorPair.first != null;
+ assert colorPair.second != null;
+ assertTrue(
+ "Expect contrast between " + String.format("#%06X", (0xFFFFFF & colorPair.first)) + " and " + String.format("#%06X", (0xFFFFFF & colorPair.second)) + " to be sufficient",
+ DeckColorUtil.contrastRatioIsSufficient(colorPair.first, colorPair.second)
+ );
+ }
+
+ final List<Pair<Integer, Integer>> insufficientContrastColorPairs = new ArrayList<>();
+ insufficientContrastColorPairs.add(new Pair<>(Color.WHITE, Color.WHITE));
+ insufficientContrastColorPairs.add(new Pair<>(Color.BLACK, Color.BLACK));
+
+ for (Pair<Integer, Integer> colorPair : insufficientContrastColorPairs) {
+ assert colorPair.first != null;
+ assert colorPair.second != null;
+ assertFalse(
+ "Expect contrast between " + String.format("#%06X", (0xFFFFFF & colorPair.first)) + " and " + String.format("#%06X", (0xFFFFFF & colorPair.second)) + " to be insufficient",
+ DeckColorUtil.contrastRatioIsSufficient(colorPair.first, colorPair.second)
+ );
+ }
+ }
+
+}
diff --git a/app/src/test/java/it/niedermann/nextcloud/deck/util/SpannableUtilTest.java b/app/src/test/java/it/niedermann/nextcloud/deck/util/SpannableUtilTest.java
new file mode 100644
index 000000000..cff0f318e
--- /dev/null
+++ b/app/src/test/java/it/niedermann/nextcloud/deck/util/SpannableUtilTest.java
@@ -0,0 +1,55 @@
+package it.niedermann.nextcloud.deck.util;
+
+import android.content.Context;
+import android.graphics.Typeface;
+import android.os.Build;
+import android.text.SpannableString;
+import android.text.style.ForegroundColorSpan;
+import android.text.style.StyleSpan;
+import android.text.style.URLSpan;
+
+import androidx.test.core.app.ApplicationProvider;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.annotation.Config;
+
+import static org.junit.Assert.assertEquals;
+
+@RunWith(RobolectricTestRunner.class)
+@Config(sdk = {Build.VERSION_CODES.P})
+public class SpannableUtilTest {
+
+ @Test
+ public void testStrong() {
+ final SpannableString spannableString = SpannableUtil.strong("test");
+ assertEquals(1, spannableString.getSpans(0, spannableString.length(), Object.class).length);
+ assertEquals(1, spannableString.getSpans(0, spannableString.length(), StyleSpan.class).length);
+ assertEquals(4, spannableString.length());
+ assertEquals(Typeface.BOLD, spannableString.getSpans(0, spannableString.length(), StyleSpan.class)[0].getStyle());
+ }
+
+ @Test
+ public void testDisabled() {
+ final Context appContext = ApplicationProvider.getApplicationContext();
+
+ final SpannableString spannableString = SpannableUtil.disabled("test", appContext);
+ assertEquals(2, spannableString.getSpans(0, spannableString.length(), Object.class).length);
+ assertEquals(1, spannableString.getSpans(0, spannableString.length(), ForegroundColorSpan.class).length);
+ assertEquals(1, spannableString.getSpans(0, spannableString.length(), StyleSpan.class).length);
+ assertEquals(4, spannableString.length());
+ assertEquals(Typeface.ITALIC, spannableString.getSpans(0, spannableString.length(), StyleSpan.class)[0].getStyle());
+ }
+
+
+ @Test
+ public void testUrl() {
+ final SpannableString spannableString = SpannableUtil.url("test", "https://example.com");
+ assertEquals(1, spannableString.getSpans(0, spannableString.length(), Object.class).length);
+ assertEquals(1, spannableString.getSpans(0, spannableString.length(), URLSpan.class).length);
+ assertEquals(4, spannableString.length());
+ assertEquals("https://example.com", spannableString.getSpans(0, spannableString.length(), URLSpan.class)[0].getURL());
+ }
+
+}