Refactor and write tests for IO tasks

pull/77/merge
Alinson S. Xavier 10 years ago
parent 3656c51e95
commit 9e410f8395

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

@ -52,17 +52,13 @@ public class ImportTest
{
private File baseDir;
private Context context;
private Context targetContext;
@Before
public void setup()
{
HabitFixtures.purgeHabits();
context = InstrumentationRegistry.getInstrumentation().getContext();
targetContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
baseDir = DatabaseHelper.getFilesDir(targetContext, "Backups");
baseDir = DatabaseHelper.getFilesDir("Backups");
if(baseDir == null) fail("baseDir should not be null");
}

@ -0,0 +1,77 @@
/*
* Copyright (C) 2016 Álinson Santos Xavier <isoron@gmail.com>
*
* This file is part of Loop Habit Tracker.
*
* Loop Habit Tracker 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.
*
* Loop Habit Tracker 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.isoron.uhabits.unit.tasks;
import android.content.Context;
import android.support.test.InstrumentationRegistry;
import android.support.test.runner.AndroidJUnit4;
import android.test.suitebuilder.annotation.SmallTest;
import android.widget.ProgressBar;
import org.isoron.uhabits.models.Habit;
import org.isoron.uhabits.tasks.ExportCSVTask;
import org.isoron.uhabits.unit.models.HabitFixtures;
import org.junit.Test;
import org.junit.runner.RunWith;
import java.io.File;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import static junit.framework.Assert.assertTrue;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.nullValue;
import static org.hamcrest.core.IsNot.not;
@RunWith(AndroidJUnit4.class)
@SmallTest
public class ExportCSVTaskTest
{
@Test
public void exportCSV() throws InterruptedException
{
Context context = InstrumentationRegistry.getContext();
final CountDownLatch latch = new CountDownLatch(1);
HabitFixtures.createNonDailyHabit();
List<Habit> habits = Habit.getAll(true);
ProgressBar bar = new ProgressBar(context);
ExportCSVTask task = new ExportCSVTask(habits, bar);
task.setListener(new ExportCSVTask.Listener()
{
@Override
public void onExportCSVFinished(String archiveFilename)
{
assertThat(archiveFilename, is(not(nullValue())));
File f = new File(archiveFilename);
assertTrue(f.exists());
assertTrue(f.canRead());
latch.countDown();
}
});
task.execute();
latch.await(30, TimeUnit.SECONDS);
}
}

@ -0,0 +1,71 @@
/*
* Copyright (C) 2016 Álinson Santos Xavier <isoron@gmail.com>
*
* This file is part of Loop Habit Tracker.
*
* Loop Habit Tracker 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.
*
* Loop Habit Tracker 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.isoron.uhabits.unit.tasks;
import android.content.Context;
import android.support.test.InstrumentationRegistry;
import android.support.test.runner.AndroidJUnit4;
import android.test.suitebuilder.annotation.SmallTest;
import android.widget.ProgressBar;
import org.isoron.uhabits.tasks.ExportDBTask;
import org.junit.Test;
import org.junit.runner.RunWith;
import java.io.File;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import static junit.framework.Assert.assertTrue;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.nullValue;
import static org.hamcrest.core.IsNot.not;
@RunWith(AndroidJUnit4.class)
@SmallTest
public class ExportDBTaskTest
{
@Test
public void exportCSV() throws InterruptedException
{
Context context = InstrumentationRegistry.getContext();
final CountDownLatch latch = new CountDownLatch(1);
ProgressBar bar = new ProgressBar(context);
ExportDBTask task = new ExportDBTask(bar);
task.setListener(new ExportDBTask.Listener()
{
@Override
public void onExportDBFinished(String filename)
{
assertThat(filename, is(not(nullValue())));
File f = new File(filename);
assertTrue(f.exists());
assertTrue(f.canRead());
latch.countDown();
}
});
task.execute();
latch.await(30, TimeUnit.SECONDS);
}
}

@ -0,0 +1,108 @@
/*
* Copyright (C) 2016 Álinson Santos Xavier <isoron@gmail.com>
*
* This file is part of Loop Habit Tracker.
*
* Loop Habit Tracker 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.
*
* Loop Habit Tracker 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.isoron.uhabits.unit.tasks;
import android.content.Context;
import android.support.annotation.NonNull;
import android.support.test.InstrumentationRegistry;
import android.support.test.runner.AndroidJUnit4;
import android.test.suitebuilder.annotation.SmallTest;
import android.widget.ProgressBar;
import org.isoron.uhabits.helpers.DatabaseHelper;
import org.isoron.uhabits.tasks.ImportDataTask;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.equalTo;
import static org.junit.Assert.fail;
@RunWith(AndroidJUnit4.class)
@SmallTest
public class ImportDataTaskTest
{
private Context context;
private File baseDir;
@Before
public void setup()
{
context = InstrumentationRegistry.getContext();
baseDir = DatabaseHelper.getFilesDir("Backups");
if(baseDir == null) fail("baseDir should not be null");
}
private void copyAssetToFile(String assetPath, File dst) throws IOException
{
InputStream in = context.getAssets().open(assetPath);
DatabaseHelper.copy(in, dst);
}
private void assertTaskResult(final int expectedResult, String assetFilename)
throws IOException, InterruptedException
{
final CountDownLatch latch = new CountDownLatch(1);
ImportDataTask task = createTask(assetFilename);
task.setListener(new ImportDataTask.Listener()
{
@Override
public void onImportFinished(int result)
{
assertThat(result, equalTo(expectedResult));
latch.countDown();
}
});
task.execute();
latch.await(30, TimeUnit.SECONDS);
}
@NonNull
private ImportDataTask createTask(String assetFilename) throws IOException
{
ProgressBar bar = new ProgressBar(context);
File file = new File(String.format("%s/%s", baseDir.getPath(), assetFilename));
copyAssetToFile(assetFilename, file);
return new ImportDataTask(file, bar);
}
@Test
public void importInvalidData() throws Throwable
{
assertTaskResult(ImportDataTask.NOT_RECOGNIZED, "icon.png");
}
@Test
public void importValidData() throws Throwable
{
assertTaskResult(ImportDataTask.SUCCESS, "loop.db");
}
}

@ -48,7 +48,7 @@ public class FilePickerDialog implements AdapterView.OnItemClickListener
void onFileSelected(File file);
}
private OnFileSelectedListener fileListener;
private OnFileSelectedListener listener;
public FilePickerDialog(Activity activity, File initialDirectory)
{
@ -81,7 +81,7 @@ public class FilePickerDialog implements AdapterView.OnItemClickListener
}
else
{
if (fileListener != null) fileListener.onFileSelected(file);
if (listener != null) listener.onFileSelected(file);
dialog.dismiss();
}
}
@ -91,9 +91,9 @@ public class FilePickerDialog implements AdapterView.OnItemClickListener
dialog.show();
}
public void setFileListener(OnFileSelectedListener fileListener)
public void setListener(OnFileSelectedListener listener)
{
this.fileListener = fileListener;
this.listener = listener;
}
private void navigateTo(File path)

@ -26,6 +26,7 @@ import android.content.SharedPreferences;
import android.net.Uri;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.support.annotation.Nullable;
import android.view.ActionMode;
import android.view.ContextMenu;
import android.view.ContextMenu.ContextMenuInfo;
@ -73,7 +74,8 @@ import java.util.List;
public class ListHabitsFragment extends Fragment
implements OnSavedListener, OnItemClickListener, OnLongClickListener, DropListener,
OnClickListener, HabitListLoader.Listener, AdapterView.OnItemLongClickListener,
HabitSelectionCallback.Listener, ImportDataTask.Listener
HabitSelectionCallback.Listener, ImportDataTask.Listener, ExportCSVTask.Listener,
ExportDBTask.Listener
{
long lastLongClick = 0;
private boolean isShortToggleEnabled;
@ -437,7 +439,7 @@ public class ListHabitsFragment extends Fragment
if(dir == null) return;
FilePickerDialog picker = new FilePickerDialog(activity, dir);
picker.setFileListener(new FilePickerDialog.OnFileSelectedListener()
picker.setListener(new FilePickerDialog.OnFileSelectedListener()
{
@Override
public void onFileSelected(File file)
@ -447,6 +449,7 @@ public class ListHabitsFragment extends Fragment
task.execute();
}
});
picker.show();
}
@ -472,11 +475,49 @@ public class ListHabitsFragment extends Fragment
public void exportAllHabits()
{
new ExportCSVTask(activity, Habit.getAll(true), progressBar).execute();
ExportCSVTask task = new ExportCSVTask(Habit.getAll(true), progressBar);
task.setListener(this);
task.execute();
}
@Override
public void onExportCSVFinished(@Nullable String archiveFilename)
{
if(archiveFilename != null)
{
Intent intent = new Intent();
intent.setAction(Intent.ACTION_SEND);
intent.setType("application/zip");
intent.putExtra(Intent.EXTRA_STREAM, Uri.fromFile(new File(archiveFilename)));
activity.startActivity(intent);
}
else
{
activity.showToast(R.string.could_not_export);
}
}
public void exportDB()
{
new ExportDBTask(activity, progressBar).execute();
ExportDBTask task = new ExportDBTask(progressBar);
task.setListener(this);
task.execute();
}
@Override
public void onExportDBFinished(@Nullable String filename)
{
if(filename != null)
{
Intent intent = new Intent();
intent.setAction(Intent.ACTION_SEND);
intent.setType("application/octet-stream");
intent.putExtra(Intent.EXTRA_STREAM, Uri.fromFile(new File(filename)));
activity.startActivity(intent);
}
else
{
activity.showToast(R.string.could_not_export);
}
}
}

@ -124,8 +124,11 @@ public class DatabaseHelper
}
@Nullable
public static File getFilesDir(Context context, String prefix)
public static File getFilesDir(String prefix)
{
Context context = HabitsApplication.getContext();
if(context == null) return null;
File chosenDir = null;
File externalFilesDirs[] = ContextCompat.getExternalFilesDirs(context, null);
if(externalFilesDirs == null) return null;

@ -19,14 +19,11 @@
package org.isoron.uhabits.tasks;
import android.content.Intent;
import android.net.Uri;
import android.os.AsyncTask;
import android.support.annotation.Nullable;
import android.view.View;
import android.widget.ProgressBar;
import org.isoron.uhabits.R;
import org.isoron.uhabits.ReplayableActivity;
import org.isoron.uhabits.helpers.DatabaseHelper;
import org.isoron.uhabits.io.HabitsCSVExporter;
import org.isoron.uhabits.models.Habit;
@ -37,17 +34,25 @@ import java.util.List;
public class ExportCSVTask extends AsyncTask<Void, Void, Void>
{
private final ReplayableActivity activity;
public interface Listener
{
void onExportCSVFinished(@Nullable String archiveFilename);
}
private ProgressBar progressBar;
private final List<Habit> selectedHabits;
String archiveFilename;
private String archiveFilename;
private ExportCSVTask.Listener listener;
public ExportCSVTask(ReplayableActivity activity, List<Habit> selectedHabits,
ProgressBar progressBar)
public ExportCSVTask(List<Habit> selectedHabits, ProgressBar progressBar)
{
this.selectedHabits = selectedHabits;
this.progressBar = progressBar;
this.activity = activity;
}
public void setListener(Listener listener)
{
this.listener = listener;
}
@Override
@ -63,19 +68,8 @@ public class ExportCSVTask extends AsyncTask<Void, Void, Void>
@Override
protected void onPostExecute(Void aVoid)
{
if(archiveFilename != null)
{
Intent intent = new Intent();
intent.setAction(Intent.ACTION_SEND);
intent.setType("application/zip");
intent.putExtra(Intent.EXTRA_STREAM, Uri.fromFile(new File(archiveFilename)));
activity.startActivity(intent);
}
else
{
activity.showToast(R.string.could_not_export);
}
if(listener != null)
listener.onExportCSVFinished(archiveFilename);
if(progressBar != null)
progressBar.setVisibility(View.GONE);
@ -86,7 +80,7 @@ public class ExportCSVTask extends AsyncTask<Void, Void, Void>
{
try
{
File dir = DatabaseHelper.getFilesDir(activity, "CSV");
File dir = DatabaseHelper.getFilesDir("CSV");
if(dir == null) return null;
HabitsCSVExporter exporter = new HabitsCSVExporter(selectedHabits, dir);

@ -19,14 +19,11 @@
package org.isoron.uhabits.tasks;
import android.content.Intent;
import android.net.Uri;
import android.os.AsyncTask;
import android.support.annotation.Nullable;
import android.view.View;
import android.widget.ProgressBar;
import org.isoron.uhabits.R;
import org.isoron.uhabits.ReplayableActivity;
import org.isoron.uhabits.helpers.DatabaseHelper;
import java.io.File;
@ -34,14 +31,23 @@ import java.io.IOException;
public class ExportDBTask extends AsyncTask<Void, Void, Void>
{
private final ReplayableActivity activity;
public interface Listener
{
void onExportDBFinished(@Nullable String filename);
}
private ProgressBar progressBar;
private String filename;
private Listener listener;
public ExportDBTask(ReplayableActivity activity, ProgressBar progressBar)
public ExportDBTask(ProgressBar progressBar)
{
this.progressBar = progressBar;
this.activity = activity;
}
public void setListener(Listener listener)
{
this.listener = listener;
}
@Override
@ -57,19 +63,8 @@ public class ExportDBTask extends AsyncTask<Void, Void, Void>
@Override
protected void onPostExecute(Void aVoid)
{
if(filename != null)
{
Intent intent = new Intent();
intent.setAction(Intent.ACTION_SEND);
intent.setType("application/octet-stream");
intent.putExtra(Intent.EXTRA_STREAM, Uri.fromFile(new File(filename)));
activity.startActivity(intent);
}
else
{
activity.showToast(R.string.could_not_export);
}
if(listener != null)
listener.onExportDBFinished(filename);
if(progressBar != null)
progressBar.setVisibility(View.GONE);
@ -82,7 +77,7 @@ public class ExportDBTask extends AsyncTask<Void, Void, Void>
try
{
File dir = DatabaseHelper.getFilesDir(activity, "Backups");
File dir = DatabaseHelper.getFilesDir("Backups");
if(dir == null) return null;
filename = DatabaseHelper.saveDatabaseCopy(dir);

@ -139,13 +139,13 @@
<string name="custom_frequency">Custom …</string>
<string name="help">Help &amp; FAQ</string>
<string name="could_not_export">Failed to export data.</string>
<string name="could_not_import">Failed to import habits from file.</string>
<string name="file_not_recognized">File type not recognized.</string>
<string name="could_not_import">Failed to import data.</string>
<string name="file_not_recognized">File not recognized.</string>
<string name="habits_imported">Habits imported successfully.</string>
<string name="import_data_summary">Supports full backups exported by this app, as well as files generated by Tickmate, HabitBull or Rewire. See FAQ for more information.</string>
<string name="full_backup_success">Full backup successfully exported.</string>
<string name="import_data">Import data</string>
<string name="export_as_csv_summary">Generates files that can be opened by spreadsheet software such as Microsoft Excel or OpenOffice Calc, but cannot be imported back.</string>
<string name="export_full_backup">Export full backup</string>
<string name="export_full_backup_summary">Generates a file that contains all your data, and that can be imported back.</string>
<string name="full_backup_success">Full backup successfully exported.</string>
<string name="import_data_summary">Supports full backups exported by this app, as well as files generated by Tickmate, HabitBull or Rewire. See FAQ for more information.</string>
<string name="export_as_csv_summary">Generates files that can be opened by spreadsheet software such as Microsoft Excel or OpenOffice Calc. This file cannot be imported back.</string>
<string name="export_full_backup_summary">Generates a file that contains all your data. This file can be imported back.</string>
</resources>
Loading…
Cancel
Save