From 1c37ec63f5dba8b6e8970614d7ff1d8dc8ff80bd Mon Sep 17 00:00:00 2001 From: Kaloyan Raev Date: Fri, 22 Dec 2017 20:00:23 +0200 Subject: [PATCH] Fixes #3: Display status icon on files and folders in Windows Explorer (#67) --- pom.xml | 2 +- src/main/java/io/goobox/sync/storj/db/DB.java | 10 + .../sync/storj/overlay/OverlayHelper.java | 94 ++++--- .../sync/storj/overlay/OverlayIcon.java | 47 ++++ .../io/goobox/sync/storj/mocks/FilesMock.java | 9 + .../sync/storj/overlay/OverlayHelperTest.java | 260 ++++++++++++++++++ 6 files changed, 385 insertions(+), 37 deletions(-) create mode 100644 src/main/java/io/goobox/sync/storj/overlay/OverlayIcon.java create mode 100644 src/test/java/io/goobox/sync/storj/overlay/OverlayHelperTest.java diff --git a/pom.xml b/pom.xml index abe197d..e6175c8 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ io.goobox goobox-sync-storj - 0.0.10 + 0.0.11 jar Goobox sync app for Storj diff --git a/src/main/java/io/goobox/sync/storj/db/DB.java b/src/main/java/io/goobox/sync/storj/db/DB.java index 3fbeb7c..36fa57d 100644 --- a/src/main/java/io/goobox/sync/storj/db/DB.java +++ b/src/main/java/io/goobox/sync/storj/db/DB.java @@ -28,6 +28,7 @@ import io.goobox.sync.common.Utils; import io.goobox.sync.storj.StorjUtil; +import io.goobox.sync.storj.overlay.OverlayHelper; import io.storj.libstorj.File; public class DB { @@ -141,6 +142,7 @@ public synchronized static void setSynced(File storjFile, Path localFile) throws syncFile.setLocalData(localFile); syncFile.setState(SyncState.SYNCED); repo().update(syncFile); + OverlayHelper.getInstance().refresh(localFile); } public synchronized static void addForDownload(File file) { @@ -157,6 +159,7 @@ public synchronized static void addForDownload(File storjFile, Path localFile) t syncFile.setLocalData(localFile); syncFile.setState(SyncState.FOR_DOWNLOAD); repo().update(syncFile); + OverlayHelper.getInstance().refresh(localFile); } public synchronized static void addForUpload(Path path) throws IOException { @@ -165,6 +168,7 @@ public synchronized static void addForUpload(Path path) throws IOException { syncFile.setLocalData(path); syncFile.setState(SyncState.FOR_UPLOAD); repo().update(syncFile); + OverlayHelper.getInstance().refresh(path); } public synchronized static void addForUpload(File storjFile, Path localFile) throws IOException { @@ -173,6 +177,7 @@ public synchronized static void addForUpload(File storjFile, Path localFile) thr syncFile.setLocalData(localFile); syncFile.setState(SyncState.FOR_UPLOAD); repo().update(syncFile); + OverlayHelper.getInstance().refresh(localFile); } public synchronized static void setDownloadFailed(File storjFile, Path localFile) throws IOException { @@ -183,6 +188,7 @@ public synchronized static void setDownloadFailed(File storjFile, Path localFile } syncFile.setState(SyncState.DOWNLOAD_FAILED); repo().update(syncFile); + OverlayHelper.getInstance().refresh(localFile); } public synchronized static void setUploadFailed(Path path) throws IOException { @@ -192,6 +198,7 @@ public synchronized static void setUploadFailed(Path path) throws IOException { } syncFile.setState(SyncState.UPLOAD_FAILED); repo().update(syncFile); + OverlayHelper.getInstance().refresh(path); } public synchronized static void setForLocalDelete(Path path) throws IOException { @@ -199,6 +206,7 @@ public synchronized static void setForLocalDelete(Path path) throws IOException syncFile.setLocalData(path); syncFile.setState(SyncState.FOR_LOCAL_DELETE); repo().update(syncFile); + OverlayHelper.getInstance().refresh(path); } public synchronized static void setForCloudDelete(File file) { @@ -220,6 +228,7 @@ public synchronized static void addForCloudCreateDir(Path path) throws IOExcepti syncFile.setLocalData(path); syncFile.setState(SyncState.FOR_CLOUD_CREATE_DIR); repo().update(syncFile); + OverlayHelper.getInstance().refresh(path); } public synchronized static void setConflict(File storjFile, Path localFile) throws IOException { @@ -228,6 +237,7 @@ public synchronized static void setConflict(File storjFile, Path localFile) thro syncFile.setLocalData(localFile); syncFile.setState(SyncState.CONFLICT); repo().update(syncFile); + OverlayHelper.getInstance().refresh(localFile); } public static void main(String[] args) { diff --git a/src/main/java/io/goobox/sync/storj/overlay/OverlayHelper.java b/src/main/java/io/goobox/sync/storj/overlay/OverlayHelper.java index fb160a3..915bd3a 100644 --- a/src/main/java/io/goobox/sync/storj/overlay/OverlayHelper.java +++ b/src/main/java/io/goobox/sync/storj/overlay/OverlayHelper.java @@ -18,9 +18,12 @@ import java.io.IOException; import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; import java.nio.file.attribute.DosFileAttributeView; import java.util.ArrayList; import java.util.List; +import java.util.stream.Stream; import com.liferay.nativity.control.NativityControl; import com.liferay.nativity.control.NativityControlUtil; @@ -34,13 +37,14 @@ import com.liferay.nativity.util.OSDetector; import io.goobox.sync.common.Utils; +import io.goobox.sync.storj.db.DB; -public class OverlayHelper { +public class OverlayHelper implements FileIconControlCallback, ContextMenuControlCallback { private NativityControl nativityControl; private FileIconControl fileIconControl; - private int stateIconId = 0; + private int globalStateIconId = OverlayIcon.NONE.id(); private static OverlayHelper instance; @@ -60,7 +64,7 @@ public void setOK() { return; } - stateIconId = 1; + globalStateIconId = OverlayIcon.OK.id(); refresh(); } @@ -69,7 +73,7 @@ public void setSynchronizing() { return; } - stateIconId = 2; + globalStateIconId = OverlayIcon.SYNCING.id(); refresh(); } @@ -78,11 +82,21 @@ public void shutdown() { return; } - stateIconId = 0; + globalStateIconId = OverlayIcon.NONE.id(); refresh(); nativityControl.disconnect(); } + public void refresh(Path path) { + if (fileIconControl != null && path != null) { + String[] pathAndParents = Stream.iterate(path, p -> p.getParent()) + .limit(Utils.getSyncDir().relativize(path).getNameCount()) + .map(Path::toString) + .toArray(String[]::new); + fileIconControl.refreshIcons(pathAndParents); + } + } + private void refresh() { fileIconControl.refreshIcons(new String[] { Utils.getSyncDir().toString() }); } @@ -98,6 +112,7 @@ private void init() { // Setting filter folders is required for Mac's Finder Sync plugin nativityControl.setFilterFolder(Utils.getSyncDir().toString()); + // Make Goobox a system folder DosFileAttributeView attr = Files.getFileAttributeView(Utils.getSyncDir(), DosFileAttributeView.class); try { attr.setSystem(true); @@ -105,46 +120,53 @@ private void init() { e.printStackTrace(); } - // FileIconControlCallback used by Windows and Mac - FileIconControlCallback fileIconControlCallback = new FileIconControlCallback() { - @Override - public int getIconForFile(String path) { - if (Utils.getSyncDir().toString().equals(path)) { - return stateIconId; - } - return 0; - } - }; - - fileIconControl = FileIconControlUtil.getFileIconControl(nativityControl, fileIconControlCallback); - + fileIconControl = FileIconControlUtil.getFileIconControl(nativityControl, this); fileIconControl.enableFileIcons(); /* Context Menus */ + ContextMenuControlUtil.getContextMenuControl(nativityControl, this); + } - ContextMenuControlCallback contextMenuControlCallback = new ContextMenuControlCallback() { - @Override - public List getContextMenuItems(String[] paths) { - ContextMenuItem contextMenuItem = new ContextMenuItem("Goobox"); - - ContextMenuAction contextMenuAction = new ContextMenuAction() { - @Override - public void onSelection(String[] paths) { - System.out.println("Context menu selection: " + String.join("; ", paths)); - } - }; - - contextMenuItem.setContextMenuAction(contextMenuAction); + /* FileIconControlCallback used by Windows and Mac */ + @Override + public int getIconForFile(String path) { + Path p = Paths.get(path); + if (!p.startsWith(Utils.getSyncDir())) { + return OverlayIcon.NONE.id(); + } else if (Utils.getSyncDir().equals(p)) { + return globalStateIconId; + } else { + try { + return Files.walk(p) + .map(DB::get) + .map(OverlayIcon::from) + .map(OverlayIcon::id) + .reduce(OverlayIcon.NONE.id(), Integer::max); + } catch (IOException e) { + e.printStackTrace(); + } + } + return 0; + } - List contextMenuItems = new ArrayList(); - contextMenuItems.add(contextMenuItem); + @Override + public List getContextMenuItems(String[] paths) { + ContextMenuItem contextMenuItem = new ContextMenuItem("Goobox"); - // Mac Finder Sync will only show the parent level of context menus - return contextMenuItems; + ContextMenuAction contextMenuAction = new ContextMenuAction() { + @Override + public void onSelection(String[] paths) { + System.out.println("Context menu selection: " + String.join("; ", paths)); } }; - ContextMenuControlUtil.getContextMenuControl(nativityControl, contextMenuControlCallback); + contextMenuItem.setContextMenuAction(contextMenuAction); + + List contextMenuItems = new ArrayList(); + contextMenuItems.add(contextMenuItem); + + // Mac Finder Sync will only show the parent level of context menus + return contextMenuItems; } } diff --git a/src/main/java/io/goobox/sync/storj/overlay/OverlayIcon.java b/src/main/java/io/goobox/sync/storj/overlay/OverlayIcon.java new file mode 100644 index 0000000..5cd9287 --- /dev/null +++ b/src/main/java/io/goobox/sync/storj/overlay/OverlayIcon.java @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2017 Kaloyan Raev + * + * 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 . + */ +package io.goobox.sync.storj.overlay; + +import io.goobox.sync.storj.db.SyncFile; + +public enum OverlayIcon { + + NONE(0), OK(1), SYNCING(2), WARNING(3), ERROR(4); + + private int id; + + private OverlayIcon(int id) { + this.id = id; + } + + public int id() { + return id; + } + + public static OverlayIcon from(SyncFile file) { + if (file == null || file.getState().isPending()) { + return OverlayIcon.SYNCING; + } else if (file.getState().isSynced()) { + return OverlayIcon.OK; + } else if (file.getState().isFailed()) { + return OverlayIcon.ERROR; + } else { + return OverlayIcon.WARNING; + } + } + +} diff --git a/src/test/java/io/goobox/sync/storj/mocks/FilesMock.java b/src/test/java/io/goobox/sync/storj/mocks/FilesMock.java index 5a7fc38..f996859 100644 --- a/src/test/java/io/goobox/sync/storj/mocks/FilesMock.java +++ b/src/test/java/io/goobox/sync/storj/mocks/FilesMock.java @@ -19,6 +19,7 @@ import java.io.IOException; import java.nio.file.DirectoryNotEmptyException; import java.nio.file.DirectoryStream; +import java.nio.file.FileVisitOption; import java.nio.file.Files; import java.nio.file.LinkOption; import java.nio.file.OpenOption; @@ -32,6 +33,7 @@ import java.util.Iterator; import java.util.List; import java.util.Set; +import java.util.stream.Stream; import io.goobox.sync.common.Utils; import mockit.Mock; @@ -152,6 +154,13 @@ public Path write(Path path, byte[] bytes, OpenOption... options) throws IOExcep return path; } + @Mock + public Stream walk(Path start, FileVisitOption... options) throws IOException { + return Stream.of(files.toArray(new FileMock[files.size()])) + .map(FileMock::getPath) + .filter(p -> p.startsWith(start)); + } + public void modifyFile(FileMock oldFile, FileMock newFile) { if (files.contains(oldFile)) { files.remove(oldFile); diff --git a/src/test/java/io/goobox/sync/storj/overlay/OverlayHelperTest.java b/src/test/java/io/goobox/sync/storj/overlay/OverlayHelperTest.java new file mode 100644 index 0000000..c4da0ec --- /dev/null +++ b/src/test/java/io/goobox/sync/storj/overlay/OverlayHelperTest.java @@ -0,0 +1,260 @@ +/* + * Copyright (C) 2017 Kaloyan Raev + * + * 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 . + */ +package io.goobox.sync.storj.overlay; + +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.runner.RunWith; + +import io.goobox.sync.storj.db.DB; +import io.goobox.sync.storj.helpers.StorjUtil; +import io.goobox.sync.storj.mocks.DBMock; +import io.goobox.sync.storj.mocks.FileMock; +import io.goobox.sync.storj.mocks.FilesMock; +import io.goobox.sync.storj.mocks.StorjMock; +import mockit.integration.junit4.JMockit; + +@RunWith(JMockit.class) +public class OverlayHelperTest { + + @BeforeClass + public static void applySharedFakes() { + new DBMock(); + } + + @Before + public void setup() { + } + + @After + public void cleanUp() { + DB.close(); + } + + @Test + public void fileNotInDB() throws Exception { + new FilesMock(FileMock.FILE_1); + + Assert.assertEquals(OverlayIcon.SYNCING.id(), getIconId(FileMock.FILE_1)); + } + + @Test + public void syncedFile() throws Exception { + new StorjMock(StorjMock.FILE_1); + new FilesMock(FileMock.FILE_1); + + DB.setSynced(StorjMock.FILE_1, FileMock.FILE_1.getPath()); + + Assert.assertEquals(OverlayIcon.OK.id(), getIconId(FileMock.FILE_1)); + } + + @Test + public void fileForUpload() throws Exception { + new FilesMock(FileMock.FILE_1); + + DB.addForUpload(FileMock.FILE_1.getPath()); + + Assert.assertEquals(OverlayIcon.SYNCING.id(), getIconId(FileMock.FILE_1)); + } + + @Test + public void fileForReUpload() throws Exception { + new StorjMock(StorjMock.FILE_1); + new FilesMock(FileMock.FILE_1); + + DB.addForUpload(StorjMock.FILE_1, FileMock.FILE_1.getPath()); + + Assert.assertEquals(OverlayIcon.SYNCING.id(), getIconId(FileMock.FILE_1)); + } + + @Test + public void fileForDownload() throws Exception { + new StorjMock(StorjMock.FILE_1); + new FilesMock(FileMock.FILE_1); + + DB.addForDownload(StorjMock.FILE_1); + + Assert.assertEquals(OverlayIcon.SYNCING.id(), getIconId(FileMock.FILE_1)); + } + + @Test + public void fileForReDownload() throws Exception { + new StorjMock(StorjMock.FILE_1); + new FilesMock(FileMock.FILE_1); + + DB.addForDownload(StorjMock.FILE_1, FileMock.FILE_1.getPath()); + + Assert.assertEquals(OverlayIcon.SYNCING.id(), getIconId(FileMock.FILE_1)); + } + + @Test + public void fileForLocalDelete() throws Exception { + new StorjMock(StorjMock.FILE_1); + new FilesMock(FileMock.FILE_1); + + DB.setSynced(StorjMock.FILE_1, FileMock.FILE_1.getPath()); + StorjUtil.deleteFile(StorjMock.FILE_1); + DB.setForLocalDelete(FileMock.FILE_1.getPath()); + + Assert.assertEquals(OverlayIcon.SYNCING.id(), getIconId(FileMock.FILE_1)); + } + + @Test + public void fileFailedDownload() throws Exception { + new StorjMock(StorjMock.FILE_1); + new FilesMock(FileMock.FILE_1); + + DB.addForDownload(StorjMock.FILE_1); + DB.setDownloadFailed(StorjMock.FILE_1, FileMock.FILE_1.getPath()); + + Assert.assertEquals(OverlayIcon.ERROR.id(), getIconId(FileMock.FILE_1)); + } + + @Test + public void fileFailedUpload() throws Exception { + new StorjMock(StorjMock.FILE_1); + new FilesMock(FileMock.FILE_1); + + DB.addForUpload(FileMock.FILE_1.getPath()); + DB.setDownloadFailed(StorjMock.FILE_1, FileMock.FILE_1.getPath()); + + Assert.assertEquals(OverlayIcon.ERROR.id(), getIconId(FileMock.FILE_1)); + } + + @Test + public void fileInConflict() throws Exception { + new StorjMock(StorjMock.FILE_1); + new FilesMock(FileMock.FILE_1); + + DB.setConflict(StorjMock.FILE_1, FileMock.FILE_1.getPath()); + + Assert.assertEquals(OverlayIcon.WARNING.id(), getIconId(FileMock.FILE_1)); + } + + @Test + public void dirForCloudCreate() throws Exception { + new FilesMock(FileMock.DIR); + + DB.addForCloudCreateDir(FileMock.DIR.getPath()); + + Assert.assertEquals(OverlayIcon.SYNCING.id(), getIconId(FileMock.DIR)); + } + + @Test + public void dirForLocalCreate() throws Exception { + new StorjMock(StorjMock.DIR); + new FilesMock(FileMock.DIR); + + DB.addForLocalCreateDir(StorjMock.DIR); + + Assert.assertEquals(OverlayIcon.SYNCING.id(), getIconId(FileMock.DIR)); + } + + @Test + public void dirAllSynced() throws Exception { + new StorjMock(StorjMock.DIR, StorjMock.SUB_FILE, StorjMock.SUB_DIR, StorjMock.SUB_SUB_FILE); + new FilesMock(FileMock.DIR, FileMock.SUB_FILE, FileMock.SUB_DIR, FileMock.SUB_SUB_FILE); + + DB.setSynced(StorjMock.DIR, FileMock.DIR.getPath()); + DB.setSynced(StorjMock.SUB_FILE, FileMock.SUB_FILE.getPath()); + DB.setSynced(StorjMock.SUB_DIR, FileMock.SUB_DIR.getPath()); + DB.setSynced(StorjMock.SUB_SUB_FILE, FileMock.SUB_SUB_FILE.getPath()); + + Assert.assertEquals(OverlayIcon.OK.id(), getIconId(FileMock.DIR)); + Assert.assertEquals(OverlayIcon.OK.id(), getIconId(FileMock.SUB_FILE)); + Assert.assertEquals(OverlayIcon.OK.id(), getIconId(FileMock.SUB_DIR)); + Assert.assertEquals(OverlayIcon.OK.id(), getIconId(FileMock.SUB_SUB_FILE)); + } + + @Test + public void subFileResyncing() throws Exception { + new StorjMock(StorjMock.DIR, StorjMock.SUB_FILE, StorjMock.SUB_DIR, StorjMock.SUB_SUB_FILE); + new FilesMock(FileMock.DIR, FileMock.SUB_FILE, FileMock.SUB_DIR, FileMock.SUB_SUB_FILE); + + DB.setSynced(StorjMock.DIR, FileMock.DIR.getPath()); + DB.setSynced(StorjMock.SUB_FILE, FileMock.SUB_FILE.getPath()); + DB.setSynced(StorjMock.SUB_DIR, FileMock.SUB_DIR.getPath()); + DB.setSynced(StorjMock.SUB_SUB_FILE, FileMock.SUB_SUB_FILE.getPath()); + DB.addForDownload(StorjMock.SUB_FILE, FileMock.SUB_FILE.getPath()); + + Assert.assertEquals(OverlayIcon.SYNCING.id(), getIconId(FileMock.DIR)); + Assert.assertEquals(OverlayIcon.SYNCING.id(), getIconId(FileMock.SUB_FILE)); + Assert.assertEquals(OverlayIcon.OK.id(), getIconId(FileMock.SUB_DIR)); + Assert.assertEquals(OverlayIcon.OK.id(), getIconId(FileMock.SUB_SUB_FILE)); + } + + @Test + public void subSubFileResyncing() throws Exception { + new StorjMock(StorjMock.DIR, StorjMock.SUB_FILE, StorjMock.SUB_DIR, StorjMock.SUB_SUB_FILE); + new FilesMock(FileMock.DIR, FileMock.SUB_FILE, FileMock.SUB_DIR, FileMock.SUB_SUB_FILE); + + DB.setSynced(StorjMock.DIR, FileMock.DIR.getPath()); + DB.setSynced(StorjMock.SUB_FILE, FileMock.SUB_FILE.getPath()); + DB.setSynced(StorjMock.SUB_DIR, FileMock.SUB_DIR.getPath()); + DB.setSynced(StorjMock.SUB_SUB_FILE, FileMock.SUB_SUB_FILE.getPath()); + DB.addForDownload(StorjMock.SUB_SUB_FILE, FileMock.SUB_SUB_FILE.getPath()); + + Assert.assertEquals(OverlayIcon.SYNCING.id(), getIconId(FileMock.DIR)); + Assert.assertEquals(OverlayIcon.OK.id(), getIconId(FileMock.SUB_FILE)); + Assert.assertEquals(OverlayIcon.SYNCING.id(), getIconId(FileMock.SUB_DIR)); + Assert.assertEquals(OverlayIcon.SYNCING.id(), getIconId(FileMock.SUB_SUB_FILE)); + } + + @Test + public void dirAllResyncing() throws Exception { + new StorjMock(StorjMock.DIR, StorjMock.SUB_FILE, StorjMock.SUB_DIR, StorjMock.SUB_SUB_FILE); + new FilesMock(FileMock.DIR, FileMock.SUB_FILE, FileMock.SUB_DIR, FileMock.SUB_SUB_FILE); + + DB.setSynced(StorjMock.DIR, FileMock.DIR.getPath()); + DB.setSynced(StorjMock.SUB_FILE, FileMock.SUB_FILE.getPath()); + DB.setSynced(StorjMock.SUB_DIR, FileMock.SUB_DIR.getPath()); + DB.setSynced(StorjMock.SUB_SUB_FILE, FileMock.SUB_SUB_FILE.getPath()); + DB.addForDownload(StorjMock.SUB_FILE, FileMock.SUB_FILE.getPath()); + DB.addForDownload(StorjMock.SUB_SUB_FILE, FileMock.SUB_SUB_FILE.getPath()); + + Assert.assertEquals(OverlayIcon.SYNCING.id(), getIconId(FileMock.DIR)); + Assert.assertEquals(OverlayIcon.SYNCING.id(), getIconId(FileMock.SUB_FILE)); + Assert.assertEquals(OverlayIcon.SYNCING.id(), getIconId(FileMock.SUB_DIR)); + Assert.assertEquals(OverlayIcon.SYNCING.id(), getIconId(FileMock.SUB_SUB_FILE)); + } + + @Test + public void subFileFailedsubSubFileResyncing() throws Exception { + new StorjMock(StorjMock.DIR, StorjMock.SUB_FILE, StorjMock.SUB_DIR, StorjMock.SUB_SUB_FILE); + new FilesMock(FileMock.DIR, FileMock.SUB_FILE, FileMock.SUB_DIR, FileMock.SUB_SUB_FILE); + + DB.setSynced(StorjMock.DIR, FileMock.DIR.getPath()); + DB.setSynced(StorjMock.SUB_FILE, FileMock.SUB_FILE.getPath()); + DB.setSynced(StorjMock.SUB_DIR, FileMock.SUB_DIR.getPath()); + DB.setSynced(StorjMock.SUB_SUB_FILE, FileMock.SUB_SUB_FILE.getPath()); + DB.setDownloadFailed(StorjMock.SUB_FILE, FileMock.SUB_FILE.getPath()); + DB.addForDownload(StorjMock.SUB_SUB_FILE, FileMock.SUB_SUB_FILE.getPath()); + + Assert.assertEquals(OverlayIcon.ERROR.id(), getIconId(FileMock.DIR)); + Assert.assertEquals(OverlayIcon.ERROR.id(), getIconId(FileMock.SUB_FILE)); + Assert.assertEquals(OverlayIcon.SYNCING.id(), getIconId(FileMock.SUB_DIR)); + Assert.assertEquals(OverlayIcon.SYNCING.id(), getIconId(FileMock.SUB_SUB_FILE)); + } + + private int getIconId(FileMock file) { + return OverlayHelper.getInstance().getIconForFile(file.getPath().toString()); + } + +}