Flatten uhabits-android into a single gradle module
BIN
uhabits-android/src/androidTest/assets/fontawesome-webfont.ttf
Normal file
BIN
uhabits-android/src/androidTest/assets/views/CanvasTest.png
Normal file
|
After Width: | Height: | Size: 24 KiB |
|
After Width: | Height: | Size: 9.0 KiB |
|
After Width: | Height: | Size: 6.3 KiB |
|
After Width: | Height: | Size: 16 KiB |
|
After Width: | Height: | Size: 9.0 KiB |
|
After Width: | Height: | Size: 10 KiB |
|
After Width: | Height: | Size: 19 KiB |
|
After Width: | Height: | Size: 21 KiB |
|
After Width: | Height: | Size: 21 KiB |
|
After Width: | Height: | Size: 16 KiB |
|
After Width: | Height: | Size: 19 KiB |
|
After Width: | Height: | Size: 18 KiB |
|
After Width: | Height: | Size: 10 KiB |
|
After Width: | Height: | Size: 15 KiB |
|
After Width: | Height: | Size: 3.1 KiB |
|
After Width: | Height: | Size: 15 KiB |
|
After Width: | Height: | Size: 585 B |
|
After Width: | Height: | Size: 545 B |
|
After Width: | Height: | Size: 583 B |
|
After Width: | Height: | Size: 1.5 KiB |
|
After Width: | Height: | Size: 1.2 KiB |
|
After Width: | Height: | Size: 5.1 KiB |
|
After Width: | Height: | Size: 5.1 KiB |
|
After Width: | Height: | Size: 12 KiB |
|
After Width: | Height: | Size: 5.2 KiB |
|
After Width: | Height: | Size: 5.2 KiB |
|
After Width: | Height: | Size: 5.2 KiB |
|
After Width: | Height: | Size: 14 KiB |
|
After Width: | Height: | Size: 2.2 KiB |
|
After Width: | Height: | Size: 1.9 KiB |
|
After Width: | Height: | Size: 1.8 KiB |
|
After Width: | Height: | Size: 7.4 KiB |
|
After Width: | Height: | Size: 7.4 KiB |
|
After Width: | Height: | Size: 7.9 KiB |
|
After Width: | Height: | Size: 7.4 KiB |
|
After Width: | Height: | Size: 24 KiB |
|
After Width: | Height: | Size: 60 KiB |
|
After Width: | Height: | Size: 1.1 KiB |
|
After Width: | Height: | Size: 5.7 KiB |
|
After Width: | Height: | Size: 14 KiB |
|
After Width: | Height: | Size: 26 KiB |
|
After Width: | Height: | Size: 20 KiB |
|
After Width: | Height: | Size: 15 KiB |
|
After Width: | Height: | Size: 6.9 KiB |
|
After Width: | Height: | Size: 8.6 KiB |
|
After Width: | Height: | Size: 11 KiB |
|
After Width: | Height: | Size: 18 KiB |
|
After Width: | Height: | Size: 11 KiB |
|
After Width: | Height: | Size: 20 KiB |
|
After Width: | Height: | Size: 33 KiB |
|
After Width: | Height: | Size: 18 KiB |
|
After Width: | Height: | Size: 35 KiB |
|
After Width: | Height: | Size: 15 KiB |
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright (C) 2016-2020 Á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.platform.gui
|
||||
|
||||
import android.graphics.Bitmap
|
||||
import org.isoron.uhabits.BaseViewTest
|
||||
import org.junit.Test
|
||||
|
||||
class AndroidCanvasTest : BaseViewTest() {
|
||||
@Test
|
||||
fun testDrawTestImage() {
|
||||
similarityCutoff = 0.0005
|
||||
val bmp = Bitmap.createBitmap(1000, 800, Bitmap.Config.ARGB_8888)
|
||||
val canvas = AndroidCanvas()
|
||||
canvas.context = testContext
|
||||
canvas.innerDensity = 2.0
|
||||
canvas.innerCanvas = android.graphics.Canvas(bmp)
|
||||
canvas.innerBitmap = bmp
|
||||
canvas.drawTestImage()
|
||||
assertRenders(bmp, "CanvasTest.png")
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,289 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
import android.appwidget.*;
|
||||
import android.content.*;
|
||||
import android.content.res.*;
|
||||
import android.os.*;
|
||||
import android.util.*;
|
||||
|
||||
import androidx.annotation.*;
|
||||
import androidx.test.filters.*;
|
||||
import androidx.test.platform.app.*;
|
||||
import androidx.test.uiautomator.*;
|
||||
|
||||
import junit.framework.*;
|
||||
|
||||
import org.isoron.uhabits.core.models.*;
|
||||
import org.isoron.uhabits.core.preferences.*;
|
||||
import org.isoron.uhabits.core.tasks.*;
|
||||
import org.isoron.uhabits.core.utils.*;
|
||||
import org.isoron.uhabits.inject.*;
|
||||
import org.isoron.uhabits.utils.*;
|
||||
import org.junit.*;
|
||||
|
||||
import java.io.*;
|
||||
import java.time.*;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.*;
|
||||
|
||||
import static androidx.test.platform.app.InstrumentationRegistry.*;
|
||||
import static androidx.test.uiautomator.UiDevice.*;
|
||||
import static org.hamcrest.CoreMatchers.*;
|
||||
import static org.hamcrest.MatcherAssert.*;
|
||||
|
||||
@MediumTest
|
||||
public class BaseAndroidTest extends TestCase
|
||||
{
|
||||
// 8:00am, January 25th, 2015 (UTC)
|
||||
public static final long FIXED_LOCAL_TIME = 1422172800000L;
|
||||
|
||||
protected Context testContext;
|
||||
|
||||
protected Context targetContext;
|
||||
|
||||
protected Preferences prefs;
|
||||
|
||||
protected HabitList habitList;
|
||||
|
||||
protected TaskRunner taskRunner;
|
||||
|
||||
protected HabitFixtures fixtures;
|
||||
|
||||
protected CountDownLatch latch;
|
||||
|
||||
protected HabitsApplicationTestComponent appComponent;
|
||||
|
||||
protected ModelFactory modelFactory;
|
||||
|
||||
protected HabitsActivityTestComponent component;
|
||||
|
||||
private boolean isDone = false;
|
||||
|
||||
private UiDevice device;
|
||||
|
||||
@Override
|
||||
@Before
|
||||
public void setUp()
|
||||
{
|
||||
if (Looper.myLooper() == null) Looper.prepare();
|
||||
device = getInstance(getInstrumentation());
|
||||
|
||||
targetContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
|
||||
testContext = InstrumentationRegistry.getInstrumentation().getContext();
|
||||
|
||||
DateUtils.setFixedLocalTime(FIXED_LOCAL_TIME);
|
||||
DateUtils.setStartDayOffset(0, 0);
|
||||
setResolution(2.0f);
|
||||
setTheme(R.style.AppBaseTheme);
|
||||
setLocale("en", "US");
|
||||
|
||||
latch = new CountDownLatch(1);
|
||||
|
||||
Context context = targetContext.getApplicationContext();
|
||||
File dbFile = DatabaseUtils.getDatabaseFile(context);
|
||||
appComponent = DaggerHabitsApplicationTestComponent
|
||||
.builder()
|
||||
.appContextModule(new AppContextModule(context))
|
||||
.habitsModule(new HabitsModule(dbFile))
|
||||
.build();
|
||||
|
||||
HabitsApplication.Companion.setComponent(appComponent);
|
||||
prefs = appComponent.getPreferences();
|
||||
habitList = appComponent.getHabitList();
|
||||
taskRunner = appComponent.getTaskRunner();
|
||||
modelFactory = appComponent.getModelFactory();
|
||||
|
||||
prefs.clear();
|
||||
|
||||
fixtures = new HabitFixtures(modelFactory, habitList);
|
||||
fixtures.purgeHabits(appComponent.getHabitList());
|
||||
Habit habit = fixtures.createEmptyHabit();
|
||||
|
||||
component = DaggerHabitsActivityTestComponent
|
||||
.builder()
|
||||
.activityContextModule(new ActivityContextModule(targetContext))
|
||||
.habitsApplicationComponent(appComponent)
|
||||
.build();
|
||||
}
|
||||
|
||||
protected void assertWidgetProviderIsInstalled(Class componentClass)
|
||||
{
|
||||
ComponentName provider =
|
||||
new ComponentName(targetContext, componentClass);
|
||||
AppWidgetManager manager = AppWidgetManager.getInstance(targetContext);
|
||||
|
||||
List<ComponentName> installedProviders = new LinkedList<>();
|
||||
for (AppWidgetProviderInfo info : manager.getInstalledProviders())
|
||||
installedProviders.add(info.provider);
|
||||
|
||||
assertThat(installedProviders, hasItems(provider));
|
||||
}
|
||||
|
||||
protected void awaitLatch() throws InterruptedException
|
||||
{
|
||||
assertTrue(latch.await(1, TimeUnit.SECONDS));
|
||||
}
|
||||
|
||||
protected void setLocale(@NonNull String language, @NonNull String country)
|
||||
{
|
||||
Locale locale = new Locale(language, country);
|
||||
Locale.setDefault(locale);
|
||||
Resources res = targetContext.getResources();
|
||||
Configuration config = res.getConfiguration();
|
||||
config.setLocale(locale);
|
||||
}
|
||||
|
||||
protected void setResolution(float r)
|
||||
{
|
||||
DisplayMetrics dm = targetContext.getResources().getDisplayMetrics();
|
||||
dm.density = r;
|
||||
dm.scaledDensity = r;
|
||||
InterfaceUtils.setFixedResolution(r);
|
||||
}
|
||||
|
||||
protected void runConcurrently(Runnable... runnableList) throws Exception
|
||||
{
|
||||
isDone = false;
|
||||
ExecutorService executor = Executors.newFixedThreadPool(100);
|
||||
List<Future> futures = new LinkedList<>();
|
||||
for (Runnable r : runnableList)
|
||||
futures.add(executor.submit(() ->
|
||||
{
|
||||
while (!isDone) r.run();
|
||||
return null;
|
||||
}));
|
||||
|
||||
Thread.sleep(3000);
|
||||
isDone = true;
|
||||
executor.shutdown();
|
||||
for(Future f : futures) f.get();
|
||||
while (!executor.isTerminated()) Thread.sleep(50);
|
||||
}
|
||||
|
||||
protected void setTheme(@StyleRes int themeId)
|
||||
{
|
||||
targetContext.setTheme(themeId);
|
||||
StyledResources.setFixedTheme(themeId);
|
||||
}
|
||||
|
||||
protected void sleep(int time)
|
||||
{
|
||||
try
|
||||
{
|
||||
Thread.sleep(time);
|
||||
}
|
||||
catch (InterruptedException e)
|
||||
{
|
||||
fail();
|
||||
}
|
||||
}
|
||||
|
||||
public long timestamp(int year, int month, int day)
|
||||
{
|
||||
GregorianCalendar cal = DateUtils.getStartOfTodayCalendar();
|
||||
cal.set(year, month, day);
|
||||
return cal.getTimeInMillis();
|
||||
}
|
||||
|
||||
protected void startTracing()
|
||||
{
|
||||
File dir = new AndroidDirFinder(targetContext).getFilesDir("Profile");
|
||||
assertNotNull(dir);
|
||||
String tracePath = dir.getAbsolutePath() + "/performance.trace";
|
||||
Log.d("PerformanceTest", String.format("Saving trace file to %s", tracePath));
|
||||
Debug.startMethodTracingSampling(tracePath, 0, 1000);
|
||||
}
|
||||
|
||||
protected void stopTracing()
|
||||
{
|
||||
Debug.stopMethodTracing();
|
||||
}
|
||||
|
||||
protected Timestamp day(int offset)
|
||||
{
|
||||
return DateUtils.getToday().minus(offset);
|
||||
}
|
||||
|
||||
|
||||
public void setSystemTime(String tz,
|
||||
int year,
|
||||
int javaMonth,
|
||||
int day,
|
||||
int hourOfDay,
|
||||
int minute) throws Exception
|
||||
{
|
||||
GregorianCalendar cal = new GregorianCalendar();
|
||||
cal.set(Calendar.SECOND, 0);
|
||||
cal.set(year, javaMonth, day, hourOfDay, minute);
|
||||
cal.setTimeZone(TimeZone.getTimeZone(tz));
|
||||
setSystemTime(cal);
|
||||
}
|
||||
|
||||
private void setSystemTime(GregorianCalendar cal) throws Exception
|
||||
{
|
||||
ZoneId tz = cal.getTimeZone().toZoneId();
|
||||
|
||||
// Set time zone (temporary)
|
||||
String command = String.format("service call alarm 3 s16 %s", tz);
|
||||
device.executeShellCommand(command);
|
||||
|
||||
// Set time zone (permanent)
|
||||
command = String.format("setprop persist.sys.timezone %s", tz);
|
||||
device.executeShellCommand(command);
|
||||
|
||||
// Set time
|
||||
String date = String.format("%02d%02d%02d%02d%02d.%02d",
|
||||
cal.get(Calendar.MONTH) + 1,
|
||||
cal.get(Calendar.DAY_OF_MONTH),
|
||||
cal.get(Calendar.HOUR_OF_DAY),
|
||||
cal.get(Calendar.MINUTE),
|
||||
cal.get(Calendar.YEAR),
|
||||
cal.get(Calendar.SECOND));
|
||||
|
||||
// Set time (method 1)
|
||||
// Run twice to override daylight saving time
|
||||
device.executeShellCommand("date " + date);
|
||||
device.executeShellCommand("date " + date);
|
||||
|
||||
// Set time (method 2)
|
||||
// Run in addition to the method above because one of these mail fail, depending
|
||||
// on the Android API version.
|
||||
command = String.format("date -u @%d", cal.getTimeInMillis() / 1000);
|
||||
device.executeShellCommand(command);
|
||||
|
||||
// Wait for system events to settle
|
||||
Thread.sleep(1000);
|
||||
}
|
||||
|
||||
private GregorianCalendar savedCalendar = null;
|
||||
|
||||
public void saveSystemTime()
|
||||
{
|
||||
savedCalendar = new GregorianCalendar();
|
||||
}
|
||||
|
||||
public void restoreSystemTime() throws Exception
|
||||
{
|
||||
if (savedCalendar == null) throw new NullPointerException();
|
||||
setSystemTime(savedCalendar);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,133 @@
|
||||
/*
|
||||
* Copyright (C) 2017 Á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;
|
||||
|
||||
import android.content.*;
|
||||
|
||||
import androidx.test.uiautomator.*;
|
||||
|
||||
import com.linkedin.android.testbutler.*;
|
||||
|
||||
import org.isoron.uhabits.core.models.*;
|
||||
import org.isoron.uhabits.core.preferences.*;
|
||||
import org.isoron.uhabits.core.ui.screens.habits.list.*;
|
||||
import org.isoron.uhabits.core.utils.*;
|
||||
import org.isoron.uhabits.inject.*;
|
||||
import org.junit.*;
|
||||
|
||||
import static androidx.test.core.app.ApplicationProvider.*;
|
||||
import static androidx.test.platform.app.InstrumentationRegistry.*;
|
||||
import static androidx.test.uiautomator.UiDevice.*;
|
||||
|
||||
public class BaseUserInterfaceTest
|
||||
{
|
||||
private static final String PKG = "org.isoron.uhabits";
|
||||
public static final String EMPTY_DESCRIPTION_HABIT_NAME = "Read books";
|
||||
|
||||
public static UiDevice device;
|
||||
|
||||
private HabitsApplicationComponent component;
|
||||
|
||||
private HabitList habitList;
|
||||
|
||||
private Preferences prefs;
|
||||
|
||||
private HabitFixtures fixtures;
|
||||
|
||||
private HabitCardListCache cache;
|
||||
|
||||
public static void startActivity(Class cls)
|
||||
{
|
||||
Intent intent = new Intent();
|
||||
intent.setComponent(new ComponentName(PKG, cls.getCanonicalName()));
|
||||
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
|
||||
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
getApplicationContext().startActivity(intent);
|
||||
}
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception
|
||||
{
|
||||
device = getInstance(getInstrumentation());
|
||||
TestButler.setup(getApplicationContext());
|
||||
TestButler.verifyAnimationsDisabled(getApplicationContext());
|
||||
|
||||
HabitsApplication app =
|
||||
(HabitsApplication) getApplicationContext().getApplicationContext();
|
||||
component = app.getComponent();
|
||||
habitList = component.getHabitList();
|
||||
prefs = component.getPreferences();
|
||||
cache = component.getHabitCardListCache();
|
||||
fixtures = new HabitFixtures(component.getModelFactory(), habitList);
|
||||
resetState();
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() throws Exception
|
||||
{
|
||||
for (int i = 0; i < 10; i++) device.pressBack();
|
||||
TestButler.teardown(getApplicationContext());
|
||||
}
|
||||
|
||||
private void resetState() throws Exception
|
||||
{
|
||||
prefs.clear();
|
||||
prefs.setFirstRun(false);
|
||||
prefs.updateLastHint(100, DateUtils.getToday());
|
||||
habitList.removeAll();
|
||||
cache.refreshAllHabits();
|
||||
Thread.sleep(1000);
|
||||
|
||||
Habit h1 = fixtures.createEmptyHabit();
|
||||
h1.setName("Wake up early");
|
||||
h1.setQuestion("Did you wake up early today?");
|
||||
h1.setDescription("test description 1");
|
||||
h1.setColor(new PaletteColor(5));
|
||||
habitList.update(h1);
|
||||
|
||||
Habit h2 = fixtures.createShortHabit();
|
||||
h2.setName("Track time");
|
||||
h2.setQuestion("Did you track your time?");
|
||||
h2.setDescription("test description 2");
|
||||
h2.setColor(new PaletteColor(5));
|
||||
habitList.update(h2);
|
||||
|
||||
Habit h3 = fixtures.createLongHabit();
|
||||
h3.setName("Meditate");
|
||||
h3.setQuestion("Did meditate today?");
|
||||
h3.setDescription("test description 3");
|
||||
h3.setColor(new PaletteColor(10));
|
||||
habitList.update(h3);
|
||||
|
||||
Habit h4 = fixtures.createEmptyHabit();
|
||||
h4.setName(EMPTY_DESCRIPTION_HABIT_NAME);
|
||||
h4.setQuestion("Did you read books today?");
|
||||
h4.setDescription("");
|
||||
h4.setColor(new PaletteColor(2));
|
||||
habitList.update(h4);
|
||||
}
|
||||
|
||||
protected void rotateDevice() throws Exception
|
||||
{
|
||||
device.setOrientationLeft();
|
||||
device.setOrientationNatural();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,198 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
import android.graphics.*;
|
||||
import android.view.*;
|
||||
import android.widget.*;
|
||||
|
||||
import androidx.annotation.*;
|
||||
import androidx.test.platform.app.*;
|
||||
|
||||
import org.isoron.uhabits.utils.*;
|
||||
import org.isoron.uhabits.widgets.*;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.*;
|
||||
|
||||
import static android.view.View.MeasureSpec.*;
|
||||
|
||||
public class BaseViewTest extends BaseAndroidTest
|
||||
{
|
||||
public double similarityCutoff = 0.00018;
|
||||
|
||||
@Override
|
||||
public void setUp()
|
||||
{
|
||||
super.setUp();
|
||||
}
|
||||
|
||||
protected void assertRenders(View view, String expectedImagePath)
|
||||
throws IOException
|
||||
{
|
||||
Bitmap actual = renderView(view);
|
||||
if(actual == null) throw new IllegalStateException("actual is null");
|
||||
assertRenders(actual, expectedImagePath);
|
||||
}
|
||||
|
||||
protected void assertRenders(Bitmap actual, String expectedImagePath) throws IOException {
|
||||
InstrumentationRegistry.getInstrumentation().waitForIdleSync();
|
||||
expectedImagePath = "views/" + expectedImagePath;
|
||||
try
|
||||
{
|
||||
Bitmap expected = getBitmapFromAssets(expectedImagePath);
|
||||
double distance = distance(actual, expected);
|
||||
if (distance > similarityCutoff)
|
||||
{
|
||||
saveBitmap(expectedImagePath, ".expected", expected);
|
||||
String path = saveBitmap(expectedImagePath, "", actual);
|
||||
fail(String.format("Image differs from expected " +
|
||||
"(distance=%f). Actual rendered " +
|
||||
"image saved to %s", distance, path));
|
||||
}
|
||||
|
||||
expected.recycle();
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
String path = saveBitmap(expectedImagePath, "", actual);
|
||||
fail(String.format("Could not open expected image. Actual " +
|
||||
"rendered image saved to %s", path));
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
@NonNull
|
||||
protected FrameLayout convertToView(BaseWidget widget,
|
||||
int width,
|
||||
int height)
|
||||
{
|
||||
widget.setDimensions(
|
||||
new WidgetDimensions(width, height, width, height));
|
||||
FrameLayout view = new FrameLayout(targetContext);
|
||||
RemoteViews remoteViews = widget.getPortraitRemoteViews();
|
||||
view.addView(remoteViews.apply(targetContext, view));
|
||||
measureView(view, width, height);
|
||||
return view;
|
||||
}
|
||||
|
||||
protected float dpToPixels(int dp)
|
||||
{
|
||||
return InterfaceUtils.dpToPixels(targetContext, dp);
|
||||
}
|
||||
|
||||
protected void measureView(View view, float width, float height)
|
||||
{
|
||||
int specWidth = makeMeasureSpec((int) width, View.MeasureSpec.EXACTLY);
|
||||
int specHeight = makeMeasureSpec((int) height, View.MeasureSpec.EXACTLY);
|
||||
|
||||
view.setLayoutParams(new ViewGroup.LayoutParams((int) width, (int) height));
|
||||
view.measure(specWidth, specHeight);
|
||||
view.layout(0, 0, view.getMeasuredWidth(), view.getMeasuredHeight());
|
||||
}
|
||||
|
||||
protected void skipAnimation(View view)
|
||||
{
|
||||
ViewPropertyAnimator animator = view.animate();
|
||||
animator.setDuration(0);
|
||||
animator.start();
|
||||
}
|
||||
|
||||
private int[] colorToArgb(int c1)
|
||||
{
|
||||
return new int[]{
|
||||
(c1 >> 24) & 0xff, //alpha
|
||||
(c1 >> 16) & 0xff, //red
|
||||
(c1 >> 8) & 0xff, //green
|
||||
(c1) & 0xff //blue
|
||||
};
|
||||
}
|
||||
|
||||
private double distance(Bitmap b1, Bitmap b2)
|
||||
{
|
||||
if (b1.getWidth() != b2.getWidth()) return 1.0;
|
||||
if (b1.getHeight() != b2.getHeight()) return 1.0;
|
||||
|
||||
Random random = new Random();
|
||||
|
||||
double distance = 0.0;
|
||||
for (int x = 0; x < b1.getWidth(); x++)
|
||||
{
|
||||
for (int y = 0; y < b1.getHeight(); y++)
|
||||
{
|
||||
if (random.nextInt(4) != 0) continue;
|
||||
|
||||
int[] argb1 = colorToArgb(b1.getPixel(x, y));
|
||||
int[] argb2 = colorToArgb(b2.getPixel(x, y));
|
||||
distance += Math.abs(argb1[0] - argb2[0]);
|
||||
distance += Math.abs(argb1[1] - argb2[1]);
|
||||
distance += Math.abs(argb1[2] - argb2[2]);
|
||||
distance += Math.abs(argb1[3] - argb2[3]);
|
||||
}
|
||||
}
|
||||
|
||||
distance /= 255.0 * 16 * b1.getWidth() * b1.getHeight();
|
||||
return distance;
|
||||
}
|
||||
|
||||
private Bitmap getBitmapFromAssets(String path) throws IOException
|
||||
{
|
||||
InputStream stream = testContext.getAssets().open(path);
|
||||
return BitmapFactory.decodeStream(stream);
|
||||
}
|
||||
|
||||
private String saveBitmap(String filename, String suffix, Bitmap bitmap)
|
||||
throws IOException
|
||||
{
|
||||
File dir = FileUtils.getSDCardDir("test-screenshots");
|
||||
if (dir == null)
|
||||
dir = new AndroidDirFinder(targetContext).getFilesDir("test-screenshots");
|
||||
if (dir == null) throw new RuntimeException(
|
||||
"Could not find suitable dir for screenshots");
|
||||
|
||||
filename = filename.replaceAll("\\.png$", suffix + ".png");
|
||||
String absolutePath =
|
||||
String.format("%s/%s", dir.getAbsolutePath(), filename);
|
||||
|
||||
File parent = new File(absolutePath).getParentFile();
|
||||
if (!parent.exists() && !parent.mkdirs()) throw new RuntimeException(
|
||||
String.format("Could not create dir: %s",
|
||||
parent.getAbsolutePath()));
|
||||
|
||||
FileOutputStream out = new FileOutputStream(absolutePath);
|
||||
bitmap.compress(Bitmap.CompressFormat.PNG, 100, out);
|
||||
|
||||
return absolutePath;
|
||||
}
|
||||
|
||||
public Bitmap renderView(View view)
|
||||
{
|
||||
int width = view.getMeasuredWidth();
|
||||
int height = view.getMeasuredHeight();
|
||||
if(view.isLayoutRequested())
|
||||
measureView(view, width, height);
|
||||
|
||||
Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
|
||||
Canvas canvas = new Canvas(bitmap);
|
||||
view.invalidate();
|
||||
view.draw(canvas);
|
||||
return bitmap;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,164 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
import org.isoron.uhabits.core.models.*;
|
||||
import org.isoron.uhabits.core.utils.DateUtils;
|
||||
|
||||
import static org.isoron.uhabits.core.models.Entry.*;
|
||||
|
||||
public class HabitFixtures
|
||||
{
|
||||
public boolean LONG_HABIT_ENTRIES[] = {
|
||||
true, false, false, true, true, true, false, false, true, true
|
||||
};
|
||||
|
||||
public int LONG_NUMERICAL_HABIT_ENTRIES[] = {
|
||||
200000, 0, 150000, 137000, 0, 0, 500000, 30000, 100000, 0, 300000,
|
||||
100000, 0, 100000
|
||||
};
|
||||
|
||||
private ModelFactory modelFactory;
|
||||
|
||||
private final HabitList habitList;
|
||||
|
||||
public HabitFixtures(ModelFactory modelFactory, HabitList habitList)
|
||||
{
|
||||
this.modelFactory = modelFactory;
|
||||
this.habitList = habitList;
|
||||
}
|
||||
|
||||
public Habit createEmptyHabit()
|
||||
{
|
||||
return createEmptyHabit(null);
|
||||
}
|
||||
|
||||
public Habit createEmptyHabit(Long id)
|
||||
{
|
||||
Habit habit = modelFactory.buildHabit();
|
||||
habit.setName("Meditate");
|
||||
habit.setQuestion("Did you meditate this morning?");
|
||||
habit.setDescription("This is a test description");
|
||||
habit.setColor(new PaletteColor(5));
|
||||
habit.setFrequency(Frequency.DAILY);
|
||||
habit.setId(id);
|
||||
habitList.add(habit);
|
||||
return habit;
|
||||
}
|
||||
|
||||
public Habit createLongHabit()
|
||||
{
|
||||
Habit habit = createEmptyHabit();
|
||||
habit.setFrequency(new Frequency(3, 7));
|
||||
habit.setColor(new PaletteColor(7));
|
||||
|
||||
Timestamp today = DateUtils.getToday();
|
||||
int marks[] = { 0, 1, 3, 5, 7, 8, 9, 10, 12, 14, 15, 17, 19, 20, 26, 27,
|
||||
28, 50, 51, 52, 53, 54, 58, 60, 63, 65, 70, 71, 72, 73, 74, 75, 80,
|
||||
81, 83, 89, 90, 91, 95, 102, 103, 108, 109, 120};
|
||||
|
||||
for (int mark : marks)
|
||||
habit.getOriginalEntries().add(new Entry(today.minus(mark), YES_MANUAL));
|
||||
|
||||
habit.recompute();
|
||||
return habit;
|
||||
}
|
||||
|
||||
public Habit createVeryLongHabit()
|
||||
{
|
||||
Habit habit = createEmptyHabit();
|
||||
habit.setFrequency(new Frequency(1, 2));
|
||||
habit.setColor(new PaletteColor(11));
|
||||
|
||||
Timestamp today = DateUtils.getToday();
|
||||
int marks[] = {0, 3, 5, 6, 7, 10, 13, 14, 15, 18, 21, 22, 23, 24, 27, 28, 30, 31, 34, 37,
|
||||
39, 42, 43, 46, 47, 48, 51, 52, 54, 55, 57, 59, 62, 65, 68, 71, 73, 76, 79,
|
||||
80, 81, 83, 85, 86, 89, 90, 91, 94, 96, 98, 100, 103, 104, 106, 109, 111,
|
||||
112, 113, 115, 117, 120, 123, 126, 129, 132, 134, 136, 139, 141, 142, 145,
|
||||
148, 149, 151, 152, 154, 156, 157, 159, 161, 162, 163, 164, 166, 168, 170,
|
||||
172, 173, 174, 175, 176, 178, 180, 181, 184, 185, 188, 189, 190, 191, 194,
|
||||
195, 197, 198, 199, 200, 202, 205, 208, 211, 213, 215, 216, 218, 220, 222,
|
||||
223, 225, 227, 228, 230, 231, 232, 234, 235, 238, 241, 242, 244, 247, 250,
|
||||
251, 253, 254, 257, 260, 261, 263, 264, 266, 269, 272, 273, 276, 279, 281,
|
||||
284, 285, 288, 291, 292, 294, 296, 297, 299, 300, 301, 303, 306, 307, 308,
|
||||
309, 310, 313, 316, 319, 322, 324, 326, 329, 330, 332, 334, 335, 337, 338,
|
||||
341, 344, 345, 346, 347, 350, 352, 355, 358, 360, 361, 362, 363, 365, 368,
|
||||
371, 373, 374, 376, 379, 380, 382, 384, 385, 387, 389, 390, 392, 393, 395,
|
||||
396, 399, 401, 404, 407, 410, 411, 413, 414, 416, 417, 419, 420, 423, 424,
|
||||
427, 429, 431, 433, 436, 439, 440, 442, 445, 447, 450, 453, 454, 456, 459,
|
||||
460, 461, 464, 466, 468, 470, 473, 474, 475, 477, 479, 481, 482, 483, 486,
|
||||
489, 491, 493, 495, 497, 498, 500, 503, 504, 507, 510, 511, 512, 515, 518,
|
||||
519, 521, 522, 525, 528, 531, 532, 534, 537, 539, 541, 543, 544, 547, 550,
|
||||
551, 554, 556, 557, 560, 561, 564, 567, 568, 569, 570, 572, 575, 576, 579,
|
||||
582, 583, 584, 586, 589};
|
||||
|
||||
for (int mark : marks)
|
||||
habit.getOriginalEntries().add(new Entry(today.minus(mark), YES_MANUAL));
|
||||
|
||||
habit.recompute();
|
||||
return habit;
|
||||
}
|
||||
|
||||
public Habit createLongNumericalHabit()
|
||||
{
|
||||
Habit habit = modelFactory.buildHabit();
|
||||
habit.setName("Read");
|
||||
habit.setQuestion("How many pages did you walk today?");
|
||||
habit.setType(Habit.NUMBER_HABIT);
|
||||
habit.setTargetType(Habit.AT_LEAST);
|
||||
habit.setTargetValue(200.0);
|
||||
habit.setUnit("pages");
|
||||
habitList.add(habit);
|
||||
|
||||
Timestamp timestamp = DateUtils.getToday();
|
||||
for (int value : LONG_NUMERICAL_HABIT_ENTRIES)
|
||||
{
|
||||
habit.getOriginalEntries().add(new Entry(timestamp, value));
|
||||
timestamp = timestamp.minus(1);
|
||||
}
|
||||
|
||||
habit.recompute();
|
||||
return habit;
|
||||
}
|
||||
|
||||
public Habit createShortHabit()
|
||||
{
|
||||
Habit habit = modelFactory.buildHabit();
|
||||
habit.setName("Wake up early");
|
||||
habit.setQuestion("Did you wake up before 6am?");
|
||||
habit.setFrequency(new Frequency(2, 3));
|
||||
habitList.add(habit);
|
||||
|
||||
Timestamp timestamp = DateUtils.getToday();
|
||||
for (boolean c : LONG_HABIT_ENTRIES)
|
||||
{
|
||||
if (c) habit.getOriginalEntries().add(new Entry(timestamp, YES_MANUAL));
|
||||
timestamp = timestamp.minus(1);
|
||||
}
|
||||
|
||||
habit.recompute();
|
||||
return habit;
|
||||
}
|
||||
|
||||
public synchronized void purgeHabits(HabitList habitList)
|
||||
{
|
||||
habitList.removeAll();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* 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
|
||||
|
||||
import dagger.Component
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
import org.isoron.uhabits.activities.habits.list.ListHabitsModule
|
||||
import org.isoron.uhabits.activities.habits.list.views.CheckmarkButtonViewFactory
|
||||
import org.isoron.uhabits.activities.habits.list.views.CheckmarkPanelViewFactory
|
||||
import org.isoron.uhabits.activities.habits.list.views.HabitCardViewFactory
|
||||
import org.isoron.uhabits.activities.habits.list.views.NumberButtonViewFactory
|
||||
import org.isoron.uhabits.activities.habits.list.views.NumberPanelViewFactory
|
||||
import org.isoron.uhabits.core.ui.screens.habits.list.ListHabitsBehavior
|
||||
import org.isoron.uhabits.inject.ActivityContextModule
|
||||
import org.isoron.uhabits.inject.ActivityScope
|
||||
import org.isoron.uhabits.inject.HabitModule
|
||||
import org.isoron.uhabits.inject.HabitsActivityModule
|
||||
import org.isoron.uhabits.inject.HabitsApplicationComponent
|
||||
import org.mockito.Mockito.mock
|
||||
|
||||
@Module
|
||||
class TestModule {
|
||||
@Provides fun ListHabitsBehavior() = mock(ListHabitsBehavior::class.java)
|
||||
}
|
||||
|
||||
@ActivityScope
|
||||
@Component(
|
||||
modules = arrayOf(
|
||||
ActivityContextModule::class,
|
||||
HabitsActivityModule::class,
|
||||
ListHabitsModule::class,
|
||||
HabitModule::class,
|
||||
TestModule::class
|
||||
),
|
||||
dependencies = arrayOf(HabitsApplicationComponent::class)
|
||||
)
|
||||
interface HabitsActivityTestComponent {
|
||||
fun getCheckmarkPanelViewFactory(): CheckmarkPanelViewFactory
|
||||
fun getHabitCardViewFactory(): HabitCardViewFactory
|
||||
fun getEntryButtonViewFactory(): CheckmarkButtonViewFactory
|
||||
fun getNumberButtonViewFactory(): NumberButtonViewFactory
|
||||
fun getNumberPanelViewFactory(): NumberPanelViewFactory
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
import androidx.test.filters.*;
|
||||
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
|
||||
import org.junit.*;
|
||||
import org.junit.runner.*;
|
||||
|
||||
import java.io.*;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.*;
|
||||
import static org.hamcrest.MatcherAssert.*;
|
||||
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
@MediumTest
|
||||
public class HabitsApplicationTest extends BaseAndroidTest
|
||||
{
|
||||
@Test
|
||||
public void test_getLogcat() throws IOException
|
||||
{
|
||||
String msg = "LOGCAT TEST";
|
||||
new RuntimeException(msg).printStackTrace();
|
||||
|
||||
String log = new AndroidBugReporter(targetContext).getLogcat();
|
||||
assertThat(log, containsString(msg));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
import org.isoron.uhabits.core.*;
|
||||
import org.isoron.uhabits.core.tasks.*;
|
||||
import org.isoron.uhabits.inject.*;
|
||||
import org.isoron.uhabits.intents.*;
|
||||
|
||||
import dagger.*;
|
||||
|
||||
@AppScope
|
||||
@Component(modules = {
|
||||
AppContextModule.class,
|
||||
HabitsModule.class,
|
||||
SingleThreadModule.class,
|
||||
})
|
||||
public interface HabitsApplicationTestComponent
|
||||
extends HabitsApplicationComponent
|
||||
{
|
||||
IntentScheduler getIntentScheduler();
|
||||
}
|
||||
|
||||
@Module
|
||||
class SingleThreadModule
|
||||
{
|
||||
@Provides
|
||||
@AppScope
|
||||
static TaskRunner provideTaskRunner()
|
||||
{
|
||||
return new SingleThreadTaskRunner();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* Copyright (C) 2017 Á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.acceptance;
|
||||
|
||||
import androidx.test.filters.*;
|
||||
import androidx.test.runner.*;
|
||||
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
|
||||
import org.isoron.uhabits.*;
|
||||
import org.junit.*;
|
||||
import org.junit.runner.*;
|
||||
|
||||
import static org.isoron.uhabits.acceptance.steps.CommonSteps.*;
|
||||
import static org.isoron.uhabits.acceptance.steps.ListHabitsSteps.MenuItem.*;
|
||||
import static org.isoron.uhabits.acceptance.steps.ListHabitsSteps.*;
|
||||
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
@LargeTest
|
||||
public class AboutTest extends BaseUserInterfaceTest
|
||||
{
|
||||
@Test
|
||||
public void shouldDisplayAboutScreen() {
|
||||
launchApp();
|
||||
clickMenu(ABOUT);
|
||||
verifyDisplaysText("Loop Habit Tracker");
|
||||
verifyDisplaysText("Rate this app on Google Play");
|
||||
verifyDisplaysText("Developers");
|
||||
verifyDisplaysText("Translators");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldDisplayAboutScreenFromSettings() {
|
||||
launchApp();
|
||||
clickMenu(SETTINGS);
|
||||
clickText("About");
|
||||
verifyDisplaysText("Translators");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* Copyright (C) 2016-2020 Á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.acceptance
|
||||
|
||||
import androidx.test.filters.LargeTest
|
||||
import org.isoron.uhabits.BaseUserInterfaceTest
|
||||
import org.isoron.uhabits.acceptance.steps.CommonSteps.clickText
|
||||
import org.isoron.uhabits.acceptance.steps.CommonSteps.launchApp
|
||||
import org.isoron.uhabits.acceptance.steps.CommonSteps.longClickText
|
||||
import org.isoron.uhabits.acceptance.steps.CommonSteps.verifyDisplaysText
|
||||
import org.isoron.uhabits.acceptance.steps.CommonSteps.verifyDoesNotDisplayText
|
||||
import org.isoron.uhabits.acceptance.steps.ListHabitsSteps
|
||||
import org.isoron.uhabits.acceptance.steps.clearBackupFolder
|
||||
import org.isoron.uhabits.acceptance.steps.clearDownloadFolder
|
||||
import org.isoron.uhabits.acceptance.steps.copyBackupToDownloadFolder
|
||||
import org.isoron.uhabits.acceptance.steps.exportFullBackup
|
||||
import org.isoron.uhabits.acceptance.steps.importBackupFromDownloadFolder
|
||||
import org.junit.Test
|
||||
|
||||
@LargeTest
|
||||
class BackupTest : BaseUserInterfaceTest() {
|
||||
@Test
|
||||
fun shouldExportAndImportBackup() {
|
||||
launchApp()
|
||||
clearDownloadFolder()
|
||||
clearBackupFolder()
|
||||
exportFullBackup()
|
||||
copyBackupToDownloadFolder()
|
||||
|
||||
longClickText("Wake up early")
|
||||
ListHabitsSteps.clickMenu(ListHabitsSteps.MenuItem.DELETE)
|
||||
clickText("Yes")
|
||||
verifyDoesNotDisplayText("Wake up early")
|
||||
|
||||
importBackupFromDownloadFolder()
|
||||
|
||||
verifyDisplaysText("Wake up early")
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,200 @@
|
||||
/*
|
||||
* Copyright (C) 2017 Á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.acceptance;
|
||||
|
||||
import androidx.test.filters.*;
|
||||
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
|
||||
import org.isoron.uhabits.*;
|
||||
import org.junit.*;
|
||||
import org.junit.runner.*;
|
||||
|
||||
import static org.isoron.uhabits.acceptance.steps.CommonSteps.Screen.*;
|
||||
import static org.isoron.uhabits.acceptance.steps.CommonSteps.*;
|
||||
import static org.isoron.uhabits.acceptance.steps.EditHabitSteps.*;
|
||||
import static org.isoron.uhabits.acceptance.steps.ListHabitsSteps.MenuItem.*;
|
||||
import static org.isoron.uhabits.acceptance.steps.ListHabitsSteps.*;
|
||||
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
@LargeTest
|
||||
public class HabitsTest extends BaseUserInterfaceTest
|
||||
{
|
||||
@Test
|
||||
public void shouldCreateHabit() throws Exception {
|
||||
shouldCreateHabit("this is a test description");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldCreateHabitBlankDescription() throws Exception {
|
||||
shouldCreateHabit("");
|
||||
}
|
||||
|
||||
private void shouldCreateHabit(String description) throws Exception
|
||||
{
|
||||
launchApp();
|
||||
|
||||
verifyShowsScreen(LIST_HABITS);
|
||||
clickMenu(ADD);
|
||||
|
||||
verifyShowsScreen(SELECT_HABIT_TYPE);
|
||||
clickText("Yes or No");
|
||||
|
||||
verifyShowsScreen(EDIT_HABIT);
|
||||
String testName = "Hello world";
|
||||
typeName(testName);
|
||||
typeQuestion("Did you say hello to the world today?");
|
||||
typeDescription(description);
|
||||
pickFrequency();
|
||||
pickColor(5);
|
||||
clickSave();
|
||||
|
||||
verifyShowsScreen(LIST_HABITS);
|
||||
verifyDisplaysText(testName);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldShowHabitStatistics() throws Exception
|
||||
{
|
||||
launchApp();
|
||||
verifyShowsScreen(LIST_HABITS);
|
||||
clickText("Track time");
|
||||
|
||||
verifyShowsScreen(SHOW_HABIT);
|
||||
verifyDisplayGraphs();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldDeleteHabit() throws Exception
|
||||
{
|
||||
launchApp();
|
||||
|
||||
verifyShowsScreen(LIST_HABITS);
|
||||
longClickText("Track time");
|
||||
clickMenu(DELETE);
|
||||
clickText("Yes");
|
||||
verifyDoesNotDisplayText("Track time");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldEditHabit() throws Exception {
|
||||
shouldEditHabit("this is a test description");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldEditHabitBlankDescription() throws Exception {
|
||||
shouldEditHabit("");
|
||||
}
|
||||
|
||||
private void shouldEditHabit(String description) throws Exception
|
||||
{
|
||||
launchApp();
|
||||
|
||||
verifyShowsScreen(LIST_HABITS);
|
||||
longClickText("Track time");
|
||||
clickMenu(EDIT);
|
||||
|
||||
verifyShowsScreen(EDIT_HABIT);
|
||||
typeName("Take a walk");
|
||||
typeQuestion("Did you take a walk today?");
|
||||
typeDescription(description);
|
||||
clickSave();
|
||||
|
||||
verifyShowsScreen(LIST_HABITS);
|
||||
verifyDisplaysTextInSequence("Wake up early", "Take a walk", "Meditate");
|
||||
verifyDoesNotDisplayText("Track time");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldEditHabit_fromStatisticsScreen() throws Exception
|
||||
{
|
||||
launchApp();
|
||||
|
||||
verifyShowsScreen(LIST_HABITS);
|
||||
clickText("Track time");
|
||||
|
||||
verifyShowsScreen(SHOW_HABIT);
|
||||
clickMenu(EDIT);
|
||||
|
||||
verifyShowsScreen(EDIT_HABIT);
|
||||
typeName("Take a walk");
|
||||
typeQuestion("Did you take a walk today?");
|
||||
pickColor(10);
|
||||
clickSave();
|
||||
|
||||
verifyShowsScreen(SHOW_HABIT);
|
||||
verifyDisplaysText("Take a walk");
|
||||
pressBack();
|
||||
|
||||
verifyShowsScreen(LIST_HABITS);
|
||||
verifyDisplaysText("Take a walk");
|
||||
verifyDoesNotDisplayText("Track time");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldArchiveAndUnarchiveHabits() throws Exception
|
||||
{
|
||||
launchApp();
|
||||
|
||||
verifyShowsScreen(LIST_HABITS);
|
||||
longClickText("Track time");
|
||||
clickMenu(ARCHIVE);
|
||||
verifyDoesNotDisplayText("Track time");
|
||||
clickMenu(TOGGLE_ARCHIVED);
|
||||
verifyDisplaysText("Track time");
|
||||
|
||||
longClickText("Track time");
|
||||
clickMenu(UNARCHIVE);
|
||||
clickMenu(TOGGLE_ARCHIVED);
|
||||
verifyDisplaysText("Track time");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldToggleCheckmarksAndUpdateScore() throws Exception
|
||||
{
|
||||
launchApp();
|
||||
verifyShowsScreen(LIST_HABITS);
|
||||
longPressCheckmarks("Wake up early", 2);
|
||||
clickText("Wake up early");
|
||||
|
||||
verifyShowsScreen(SHOW_HABIT);
|
||||
verifyDisplaysText("10%");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldHideCompleted() throws Exception
|
||||
{
|
||||
launchApp();
|
||||
verifyShowsScreen(LIST_HABITS);
|
||||
verifyDisplaysText("Track time");
|
||||
verifyDisplaysText("Wake up early");
|
||||
|
||||
clickMenu(TOGGLE_COMPLETED);
|
||||
verifyDoesNotDisplayText("Track time");
|
||||
verifyDisplaysText("Wake up early");
|
||||
|
||||
longPressCheckmarks("Wake up early", 1);
|
||||
verifyDoesNotDisplayText("Wake up early");
|
||||
|
||||
clickMenu(TOGGLE_COMPLETED);
|
||||
verifyDisplaysText("Track time");
|
||||
verifyDisplaysText("Wake up early");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
/*
|
||||
* Copyright (C) 2017 Á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.acceptance;
|
||||
|
||||
import androidx.test.filters.*;
|
||||
import androidx.test.runner.*;
|
||||
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
|
||||
import org.isoron.uhabits.*;
|
||||
import org.junit.*;
|
||||
import org.junit.runner.*;
|
||||
|
||||
import static org.isoron.uhabits.acceptance.steps.CommonSteps.*;
|
||||
import static org.isoron.uhabits.acceptance.steps.ListHabitsSteps.MenuItem.*;
|
||||
import static org.isoron.uhabits.acceptance.steps.ListHabitsSteps.*;
|
||||
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
@LargeTest
|
||||
public class LinksTest extends BaseUserInterfaceTest
|
||||
{
|
||||
@Test
|
||||
public void shouldLinkToSourceCode() throws Exception
|
||||
{
|
||||
launchApp();
|
||||
clickMenu(ABOUT);
|
||||
clickText("View source code at GitHub");
|
||||
verifyOpensWebsite("github.com");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldLinkToTranslationWebsite() throws Exception
|
||||
{
|
||||
launchApp();
|
||||
clickMenu(ABOUT);
|
||||
clickText("Help translate this app");
|
||||
verifyOpensWebsite("translate.loophabits.org");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldLinkToHelp() throws Exception {
|
||||
launchApp();
|
||||
clickMenu(HELP);
|
||||
verifyOpensWebsite("github.com");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldLinkToHelpFromSettings() throws Exception {
|
||||
launchApp();
|
||||
clickMenu(SETTINGS);
|
||||
clickText("Help & FAQ");
|
||||
verifyOpensWebsite("github.com");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* Copyright (C) 2017 Á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.acceptance;
|
||||
|
||||
import androidx.test.filters.*;
|
||||
|
||||
import org.isoron.uhabits.*;
|
||||
import org.junit.*;
|
||||
|
||||
import static org.isoron.uhabits.acceptance.steps.CommonSteps.*;
|
||||
import static org.isoron.uhabits.acceptance.steps.WidgetSteps.*;
|
||||
import static org.isoron.uhabits.acceptance.steps.WidgetSteps.clickText;
|
||||
|
||||
@LargeTest
|
||||
public class WidgetTest extends BaseUserInterfaceTest
|
||||
{
|
||||
@Test
|
||||
public void shouldCreateAndToggleCheckmarkWidget() throws Exception
|
||||
{
|
||||
dragCheckmarkWidgetToHomeScreen();
|
||||
Thread.sleep(3000);
|
||||
clickText("Wake up early");
|
||||
clickText("Save");
|
||||
verifyCheckmarkWidgetIsShown();
|
||||
clickCheckmarkWidget();
|
||||
|
||||
launchApp();
|
||||
clickText("Wake up early");
|
||||
verifyDisplaysText("5%");
|
||||
|
||||
pressHome();
|
||||
clickCheckmarkWidget();
|
||||
|
||||
launchApp();
|
||||
clickText("Wake up early");
|
||||
verifyDisplaysText("0%");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* Copyright (C) 2016-2020 Á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.acceptance.steps
|
||||
|
||||
import androidx.test.uiautomator.UiSelector
|
||||
import org.isoron.uhabits.acceptance.steps.CommonSteps.clickText
|
||||
import org.isoron.uhabits.acceptance.steps.CommonSteps.device
|
||||
import org.isoron.uhabits.acceptance.steps.ListHabitsSteps.MenuItem.SETTINGS
|
||||
import org.isoron.uhabits.acceptance.steps.ListHabitsSteps.clickMenu
|
||||
|
||||
const val BACKUP_FOLDER = "/sdcard/Android/data/org.isoron.uhabits/files/Backups/"
|
||||
const val DOWNLOAD_FOLDER = "/sdcard/Download/"
|
||||
|
||||
fun exportFullBackup() {
|
||||
clickMenu(SETTINGS)
|
||||
clickText("Export full backup")
|
||||
device.pressBack()
|
||||
}
|
||||
|
||||
fun clearDownloadFolder() {
|
||||
device.executeShellCommand("rm -rf /sdcard/Download/")
|
||||
}
|
||||
|
||||
fun clearBackupFolder() {
|
||||
device.executeShellCommand("rm -rf $BACKUP_FOLDER")
|
||||
}
|
||||
|
||||
fun copyBackupToDownloadFolder() {
|
||||
device.executeShellCommand("mv $BACKUP_FOLDER $DOWNLOAD_FOLDER")
|
||||
device.executeShellCommand("chown root $DOWNLOAD_FOLDER")
|
||||
}
|
||||
|
||||
fun importBackupFromDownloadFolder() {
|
||||
clickMenu(SETTINGS)
|
||||
clickText("Import data")
|
||||
device.click(100, 180) // Click menu button
|
||||
device.findObject(UiSelector().textContains("Download")).click()
|
||||
device.findObject(UiSelector().textContains("Loop")).click()
|
||||
}
|
||||
|
||||
fun openLauncher() {
|
||||
device.pressHome()
|
||||
device.waitForIdle()
|
||||
val h = device.displayHeight
|
||||
val w = device.displayWidth
|
||||
device.swipe(w / 2, h / 2, w / 2, 0, 8)
|
||||
}
|
||||
@@ -0,0 +1,177 @@
|
||||
/*
|
||||
* Copyright (C) 2017 Á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.acceptance.steps;
|
||||
|
||||
import android.view.*;
|
||||
|
||||
import androidx.annotation.*;
|
||||
import androidx.recyclerview.widget.*;
|
||||
import androidx.test.espresso.*;
|
||||
import androidx.test.espresso.contrib.*;
|
||||
import androidx.test.uiautomator.*;
|
||||
|
||||
import org.hamcrest.*;
|
||||
import org.isoron.uhabits.*;
|
||||
import org.isoron.uhabits.R;
|
||||
import org.isoron.uhabits.activities.habits.list.*;
|
||||
|
||||
import static android.os.Build.VERSION.*;
|
||||
import static androidx.test.espresso.Espresso.*;
|
||||
import static androidx.test.espresso.action.ViewActions.*;
|
||||
import static androidx.test.espresso.assertion.PositionAssertions.*;
|
||||
import static androidx.test.espresso.assertion.ViewAssertions.*;
|
||||
import static androidx.test.espresso.matcher.ViewMatchers.*;
|
||||
import static org.hamcrest.CoreMatchers.*;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
public class CommonSteps extends BaseUserInterfaceTest
|
||||
{
|
||||
public static void pressBack()
|
||||
{
|
||||
device.pressBack();
|
||||
}
|
||||
|
||||
public static void clickText(String text)
|
||||
{
|
||||
scrollToText(text);
|
||||
onView(withText(text)).perform(click());
|
||||
}
|
||||
|
||||
public static void clickText(@StringRes int id)
|
||||
{
|
||||
onView(withText(id)).perform(click());
|
||||
}
|
||||
|
||||
public static void launchApp()
|
||||
{
|
||||
startActivity(ListHabitsActivity.class);
|
||||
assertTrue(
|
||||
device.wait(Until.hasObject(By.pkg("org.isoron.uhabits")), 5000));
|
||||
device.waitForIdle();
|
||||
}
|
||||
|
||||
public static void longClickText(String text)
|
||||
{
|
||||
scrollToText(text);
|
||||
onView(withText(text)).perform(longClick());
|
||||
}
|
||||
|
||||
public static void pressHome()
|
||||
{
|
||||
device.pressHome();
|
||||
device.waitForIdle();
|
||||
}
|
||||
|
||||
public static void scrollToText(String text)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (device
|
||||
.findObject(new UiSelector().className(RecyclerView.class))
|
||||
.exists())
|
||||
{
|
||||
onView(instanceOf(RecyclerView.class)).perform(
|
||||
RecyclerViewActions.scrollTo(
|
||||
hasDescendant(withText(text))));
|
||||
}
|
||||
else
|
||||
{
|
||||
onView(withText(text)).perform(scrollTo());
|
||||
}
|
||||
}
|
||||
catch (PerformException e)
|
||||
{
|
||||
//ignored
|
||||
}
|
||||
}
|
||||
|
||||
public static void verifyDisplayGraphs()
|
||||
{
|
||||
verifyDisplaysView("HistoryCard");
|
||||
verifyDisplaysView("ScoreCard");
|
||||
}
|
||||
|
||||
public static void verifyDisplaysText(String text)
|
||||
{
|
||||
scrollToText(text);
|
||||
onView(withText(text)).check(matches(isEnabled()));
|
||||
}
|
||||
|
||||
public static void verifyDisplaysTextInSequence(String... text)
|
||||
{
|
||||
verifyDisplaysText(text[0]);
|
||||
for(int i = 1; i < text.length; i++) {
|
||||
verifyDisplaysText(text[i]);
|
||||
onView(withText(text[i])).check(isCompletelyBelow(withText(text[i-1])));
|
||||
}
|
||||
}
|
||||
|
||||
private static void verifyDisplaysView(String className)
|
||||
{
|
||||
onView(withClassName(endsWith(className))).check(matches(isEnabled()));
|
||||
}
|
||||
|
||||
public static void verifyDoesNotDisplayText(String text)
|
||||
{
|
||||
onView(withText(text)).check(doesNotExist());
|
||||
}
|
||||
|
||||
public static void verifyOpensWebsite(String url) throws Exception
|
||||
{
|
||||
String browser_pkg = "org.chromium.webview_shell";
|
||||
if(SDK_INT <= 23) {
|
||||
browser_pkg = "com.android.browser";
|
||||
}
|
||||
assertTrue(device.wait(Until.hasObject(By.pkg(browser_pkg)), 5000));
|
||||
device.waitForIdle();
|
||||
assertTrue(device.findObject(new UiSelector().textContains(url)).exists());
|
||||
}
|
||||
|
||||
public enum Screen
|
||||
{
|
||||
LIST_HABITS, SHOW_HABIT, EDIT_HABIT, SELECT_HABIT_TYPE
|
||||
}
|
||||
|
||||
public static void verifyShowsScreen(Screen screen)
|
||||
{
|
||||
switch(screen)
|
||||
{
|
||||
case LIST_HABITS:
|
||||
onView(withClassName(endsWith("ListHabitsRootView")))
|
||||
.check(matches(isDisplayed()));
|
||||
break;
|
||||
|
||||
case SHOW_HABIT:
|
||||
onView(withId(R.id.subtitleCard)).check(matches(isDisplayed()));
|
||||
break;
|
||||
|
||||
case EDIT_HABIT:
|
||||
onView(withId(R.id.questionInput)).check(matches(isDisplayed()));
|
||||
break;
|
||||
|
||||
case SELECT_HABIT_TYPE:
|
||||
onView(withText(R.string.yes_or_no_example)).check(matches(isDisplayed()));
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,92 @@
|
||||
/*
|
||||
* Copyright (C) 2017 Á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.acceptance.steps;
|
||||
|
||||
import androidx.test.uiautomator.*;
|
||||
|
||||
import org.isoron.uhabits.*;
|
||||
|
||||
import static androidx.test.espresso.Espresso.*;
|
||||
import static androidx.test.espresso.action.ViewActions.*;
|
||||
import static androidx.test.espresso.action.ViewActions.closeSoftKeyboard;
|
||||
import static androidx.test.espresso.matcher.ViewMatchers.*;
|
||||
import static org.isoron.uhabits.BaseUserInterfaceTest.*;
|
||||
|
||||
public class EditHabitSteps
|
||||
{
|
||||
public static void clickSave()
|
||||
{
|
||||
onView(withId(R.id.buttonSave)).perform(click());
|
||||
}
|
||||
|
||||
public static void pickFrequency()
|
||||
{
|
||||
onView(withId(R.id.boolean_frequency_picker)).perform(click());
|
||||
onView(withText("SAVE")).perform(click());
|
||||
}
|
||||
|
||||
public static void pickColor(int color)
|
||||
{
|
||||
onView(withId(R.id.colorButton)).perform(click());
|
||||
device.findObject(By.descStartsWith(String.format("Color %d", color))).click();
|
||||
}
|
||||
|
||||
public static void typeName(String name)
|
||||
{
|
||||
typeTextWithId(R.id.nameInput, name);
|
||||
}
|
||||
|
||||
public static void typeQuestion(String name)
|
||||
{
|
||||
typeTextWithId(R.id.questionInput, name);
|
||||
}
|
||||
|
||||
public static void typeDescription(String description)
|
||||
{
|
||||
typeTextWithId(R.id.notesInput, description);
|
||||
}
|
||||
|
||||
public static void setReminder()
|
||||
{
|
||||
onView(withId(R.id.reminderTimePicker)).perform(click());
|
||||
onView(withId(R.id.done_button)).perform(click());
|
||||
}
|
||||
|
||||
public static void clickReminderDays()
|
||||
{
|
||||
onView(withId(R.id.reminderDatePicker)).perform(click());
|
||||
}
|
||||
|
||||
public static void unselectAllDays()
|
||||
{
|
||||
onView(withText("Saturday")).perform(click());
|
||||
onView(withText("Sunday")).perform(click());
|
||||
onView(withText("Monday")).perform(click());
|
||||
onView(withText("Tuesday")).perform(click());
|
||||
onView(withText("Wednesday")).perform(click());
|
||||
onView(withText("Thursday")).perform(click());
|
||||
onView(withText("Friday")).perform(click());
|
||||
}
|
||||
|
||||
private static void typeTextWithId(int id, String name)
|
||||
{
|
||||
onView(withId(id)).perform(clearText(), typeText(name), closeSoftKeyboard());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,161 @@
|
||||
/*
|
||||
* Copyright (C) 2017 Á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.acceptance.steps;
|
||||
|
||||
import androidx.test.espresso.*;
|
||||
import android.view.*;
|
||||
|
||||
import org.hamcrest.*;
|
||||
import org.isoron.uhabits.R;
|
||||
import org.isoron.uhabits.activities.habits.list.views.*;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import static androidx.test.espresso.Espresso.onView;
|
||||
import static androidx.test.espresso.action.ViewActions.click;
|
||||
import static androidx.test.espresso.matcher.ViewMatchers.hasDescendant;
|
||||
import static androidx.test.espresso.matcher.ViewMatchers.isEnabled;
|
||||
import static androidx.test.espresso.matcher.ViewMatchers.withClassName;
|
||||
import static androidx.test.espresso.matcher.ViewMatchers.withContentDescription;
|
||||
import static androidx.test.espresso.matcher.ViewMatchers.withId;
|
||||
import static androidx.test.espresso.matcher.ViewMatchers.withParent;
|
||||
import static androidx.test.espresso.matcher.ViewMatchers.withText;
|
||||
import static org.hamcrest.CoreMatchers.*;
|
||||
import static org.isoron.uhabits.BaseUserInterfaceTest.device;
|
||||
import static org.isoron.uhabits.acceptance.steps.CommonSteps.clickText;
|
||||
|
||||
public abstract class ListHabitsSteps
|
||||
{
|
||||
public static void clickMenu(MenuItem item)
|
||||
{
|
||||
switch (item)
|
||||
{
|
||||
case ABOUT:
|
||||
clickTextInsideOverflowMenu(R.string.about);
|
||||
break;
|
||||
|
||||
case HELP:
|
||||
clickTextInsideOverflowMenu(R.string.help);
|
||||
break;
|
||||
|
||||
case SETTINGS:
|
||||
clickTextInsideOverflowMenu(R.string.settings);
|
||||
break;
|
||||
|
||||
case ADD:
|
||||
clickViewWithId(R.id.actionCreateHabit);
|
||||
break;
|
||||
|
||||
case EDIT:
|
||||
clickViewWithId(R.id.action_edit_habit);
|
||||
break;
|
||||
|
||||
case DELETE:
|
||||
clickTextInsideOverflowMenu(R.string.delete);
|
||||
break;
|
||||
|
||||
case ARCHIVE:
|
||||
clickTextInsideOverflowMenu(R.string.archive);
|
||||
break;
|
||||
|
||||
case UNARCHIVE:
|
||||
clickTextInsideOverflowMenu(R.string.unarchive);
|
||||
break;
|
||||
|
||||
case TOGGLE_ARCHIVED:
|
||||
clickViewWithId(R.id.action_filter);
|
||||
clickText(R.string.hide_archived);
|
||||
break;
|
||||
|
||||
case TOGGLE_COMPLETED:
|
||||
clickViewWithId(R.id.action_filter);
|
||||
clickText(R.string.hide_completed);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private static void clickTextInsideOverflowMenu(int id) {
|
||||
onView(allOf(withContentDescription("More options"), withParent(withParent(withClassName(endsWith("Toolbar")))))).perform(click());
|
||||
onView(withText(id)).perform(click());
|
||||
}
|
||||
|
||||
private static void clickViewWithId(int id)
|
||||
{
|
||||
onView(withId(id)).perform(click());
|
||||
}
|
||||
|
||||
private static ViewAction longClickDescendantWithClass(Class cls, int count)
|
||||
{
|
||||
return new ViewAction()
|
||||
{
|
||||
|
||||
@Override
|
||||
public Matcher<View> getConstraints()
|
||||
{
|
||||
return isEnabled();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDescription()
|
||||
{
|
||||
return "perform on children";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void perform(UiController uiController, View view)
|
||||
{
|
||||
LinkedList<ViewGroup> stack = new LinkedList<>();
|
||||
if (view instanceof ViewGroup) stack.push((ViewGroup) view);
|
||||
int countRemaining = count;
|
||||
|
||||
while (!stack.isEmpty())
|
||||
{
|
||||
ViewGroup vg = stack.pop();
|
||||
for (int i = 0; i < vg.getChildCount(); i++)
|
||||
{
|
||||
View v = vg.getChildAt(i);
|
||||
if (v instanceof ViewGroup) stack.push((ViewGroup) v);
|
||||
if (cls.isInstance(v) && countRemaining > 0)
|
||||
{
|
||||
v.performLongClick();
|
||||
uiController.loopMainThreadUntilIdle();
|
||||
countRemaining--;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public static void longPressCheckmarks(String habit, int count)
|
||||
{
|
||||
CommonSteps.scrollToText(habit);
|
||||
onView(allOf(hasDescendant(withText(habit)),
|
||||
withClassName(endsWith("HabitCardView")))).perform(
|
||||
longClickDescendantWithClass(CheckmarkButtonView.class, count));
|
||||
device.waitForIdle();
|
||||
}
|
||||
|
||||
public enum MenuItem
|
||||
{
|
||||
ABOUT, HELP, SETTINGS, EDIT, DELETE, ARCHIVE, TOGGLE_ARCHIVED,
|
||||
UNARCHIVE, TOGGLE_COMPLETED, ADD
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
/*
|
||||
* Copyright (C) 2017 Á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.acceptance.steps;
|
||||
|
||||
import androidx.test.uiautomator.*;
|
||||
|
||||
import static android.os.Build.VERSION.SDK_INT;
|
||||
import static org.junit.Assert.*;
|
||||
import static org.isoron.uhabits.BaseUserInterfaceTest.*;
|
||||
|
||||
public class WidgetSteps {
|
||||
public static void clickCheckmarkWidget() throws Exception {
|
||||
String view_id = "org.isoron.uhabits:id/imageView";
|
||||
device.findObject(new UiSelector().resourceId(view_id)).click();
|
||||
}
|
||||
|
||||
public static void clickText(String s) throws Exception {
|
||||
UiObject object = device.findObject(new UiSelector().text(s));
|
||||
if (!object.waitForExists(1000)) {
|
||||
object = device.findObject(new UiSelector().text(s.toUpperCase()));
|
||||
}
|
||||
object.click();
|
||||
}
|
||||
|
||||
public static void dragCheckmarkWidgetToHomeScreen() throws Exception {
|
||||
openWidgetScreen();
|
||||
dragWidgetToHomeScreen();
|
||||
}
|
||||
|
||||
private static void dragWidgetToHomeScreen() throws Exception {
|
||||
int height = device.getDisplayHeight();
|
||||
int width = device.getDisplayWidth();
|
||||
device.findObject(new UiSelector().text("Checkmark"))
|
||||
.dragTo(width / 2, height / 2, 40);
|
||||
}
|
||||
|
||||
private static void openWidgetScreen() throws Exception {
|
||||
int h = device.getDisplayHeight();
|
||||
int w = device.getDisplayWidth();
|
||||
if (SDK_INT <= 21) {
|
||||
device.pressHome();
|
||||
device.waitForIdle();
|
||||
device.findObject(new UiSelector().description("Apps")).click();
|
||||
device.findObject(new UiSelector().description("Apps")).click();
|
||||
device.findObject(new UiSelector().description("Widgets")).click();
|
||||
} else {
|
||||
String list_id = "com.android.launcher3:id/widgets_list_view";
|
||||
device.pressHome();
|
||||
device.waitForIdle();
|
||||
device.drag(w / 2, h / 2, w / 2, h / 2, 8);
|
||||
UiObject button = device.findObject(new UiSelector().text("WIDGETS"));
|
||||
if(!button.waitForExists(1000)) {
|
||||
button = device.findObject(new UiSelector().text("Widgets"));
|
||||
}
|
||||
button.click();
|
||||
if (SDK_INT >= 28) {
|
||||
new UiScrollable(new UiSelector().resourceId(list_id))
|
||||
.scrollForward();
|
||||
}
|
||||
new UiScrollable(new UiSelector().resourceId(list_id))
|
||||
.scrollIntoView(new UiSelector().text("Checkmark"));
|
||||
}
|
||||
}
|
||||
|
||||
public static void verifyCheckmarkWidgetIsShown() throws Exception {
|
||||
String view_id = "org.isoron.uhabits:id/imageView";
|
||||
assertTrue(device.findObject(new UiSelector().resourceId(view_id)).exists());
|
||||
assertFalse(device.findObject(new UiSelector().textStartsWith("Habit deleted")).exists());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
/*
|
||||
* 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.activities.common.views;
|
||||
|
||||
import androidx.test.ext.junit.runners.*;
|
||||
import androidx.test.filters.*;
|
||||
|
||||
import org.isoron.uhabits.*;
|
||||
import org.isoron.uhabits.core.models.*;
|
||||
import org.isoron.uhabits.utils.*;
|
||||
import org.junit.*;
|
||||
import org.junit.runner.*;
|
||||
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
@MediumTest
|
||||
public class FrequencyChartTest extends BaseViewTest
|
||||
{
|
||||
public static final String BASE_PATH = "common/FrequencyChart/";
|
||||
|
||||
private FrequencyChart view;
|
||||
|
||||
@Override
|
||||
@Before
|
||||
public void setUp()
|
||||
{
|
||||
super.setUp();
|
||||
|
||||
fixtures.purgeHabits(habitList);
|
||||
Habit habit = fixtures.createLongHabit();
|
||||
|
||||
view = new FrequencyChart(targetContext);
|
||||
view.setFrequency(habit.getOriginalEntries().computeWeekdayFrequency(
|
||||
habit.isNumerical()
|
||||
));
|
||||
view.setColor(PaletteUtilsKt.toFixedAndroidColor(habit.getColor()));
|
||||
measureView(view, dpToPixels(300), dpToPixels(100));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRender() throws Throwable
|
||||
{
|
||||
assertRenders(view, BASE_PATH + "render.png");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRender_withDataOffset() throws Throwable
|
||||
{
|
||||
view.onScroll(null, null, -dpToPixels(150), 0);
|
||||
view.invalidate();
|
||||
|
||||
assertRenders(view, BASE_PATH + "renderDataOffset.png");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRender_withDifferentSize() throws Throwable
|
||||
{
|
||||
measureView(view, dpToPixels(200), dpToPixels(200));
|
||||
assertRenders(view, BASE_PATH + "renderDifferentSize.png");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRender_withTransparentBackground() throws Throwable
|
||||
{
|
||||
view.setIsBackgroundTransparent(true);
|
||||
assertRenders(view, BASE_PATH + "renderTransparent.png");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
/*
|
||||
* 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.activities.common.views;
|
||||
|
||||
import android.graphics.*;
|
||||
import androidx.test.filters.*;
|
||||
import androidx.test.runner.*;
|
||||
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
|
||||
import org.isoron.uhabits.*;
|
||||
import org.isoron.uhabits.utils.*;
|
||||
import org.junit.*;
|
||||
import org.junit.runner.*;
|
||||
|
||||
import java.io.*;
|
||||
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
@MediumTest
|
||||
public class RingViewTest extends BaseViewTest
|
||||
{
|
||||
private static final String BASE_PATH = "common/RingView/";
|
||||
|
||||
private RingView view;
|
||||
|
||||
@Override
|
||||
@Before
|
||||
public void setUp()
|
||||
{
|
||||
super.setUp();
|
||||
|
||||
view = new RingView(targetContext);
|
||||
view.setPercentage(0.6f);
|
||||
view.setText("60%");
|
||||
view.setColor(PaletteUtils.getAndroidTestColor(0));
|
||||
view.setBackgroundColor(Color.WHITE);
|
||||
view.setThickness(dpToPixels(3));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRender_base() throws IOException
|
||||
{
|
||||
measureView(view, dpToPixels(100), dpToPixels(100));
|
||||
assertRenders(view, BASE_PATH + "render.png");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRender_withDifferentParams() throws IOException
|
||||
{
|
||||
view.setPercentage(0.25f);
|
||||
view.setColor(PaletteUtils.getAndroidTestColor(5));
|
||||
|
||||
measureView(view, dpToPixels(200), dpToPixels(200));
|
||||
assertRenders(view, BASE_PATH + "renderDifferentParams.png");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,109 @@
|
||||
/*
|
||||
* 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.activities.common.views;
|
||||
|
||||
import androidx.test.ext.junit.runners.*;
|
||||
import androidx.test.filters.*;
|
||||
|
||||
import org.isoron.uhabits.*;
|
||||
import org.isoron.uhabits.core.models.*;
|
||||
import org.isoron.uhabits.core.ui.screens.habits.show.views.*;
|
||||
import org.isoron.uhabits.utils.*;
|
||||
import org.junit.*;
|
||||
import org.junit.runner.*;
|
||||
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
@MediumTest
|
||||
public class ScoreChartTest extends BaseViewTest
|
||||
{
|
||||
private static final String BASE_PATH = "common/ScoreChart/";
|
||||
|
||||
private Habit habit;
|
||||
|
||||
private ScoreChart view;
|
||||
|
||||
@Override
|
||||
@Before
|
||||
public void setUp()
|
||||
{
|
||||
super.setUp();
|
||||
|
||||
fixtures.purgeHabits(habitList);
|
||||
habit = fixtures.createLongHabit();
|
||||
ScoreCardState state = ScoreCardPresenter.Companion.buildState(habit, prefs.getFirstWeekdayInt(), 0);
|
||||
|
||||
view = new ScoreChart(targetContext);
|
||||
view.setScores(state.getScores());
|
||||
view.setColor(PaletteUtilsKt.toFixedAndroidColor(state.getColor()));
|
||||
view.setBucketSize(state.getBucketSize());
|
||||
measureView(view, dpToPixels(300), dpToPixels(200));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRender() throws Throwable
|
||||
{
|
||||
assertRenders(view, BASE_PATH + "render.png");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRender_withDataOffset() throws Throwable
|
||||
{
|
||||
view.onScroll(null, null, -dpToPixels(150), 0);
|
||||
view.invalidate();
|
||||
|
||||
assertRenders(view, BASE_PATH + "renderDataOffset.png");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRender_withDifferentSize() throws Throwable
|
||||
{
|
||||
measureView(view, dpToPixels(200), dpToPixels(200));
|
||||
assertRenders(view, BASE_PATH + "renderDifferentSize.png");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRender_withMonthlyBucket() throws Throwable
|
||||
{
|
||||
ScoreCardState model = ScoreCardPresenter.Companion.buildState(habit, prefs.getFirstWeekdayInt(), 2);
|
||||
view.setScores(model.getScores());
|
||||
view.setBucketSize(model.getBucketSize());
|
||||
view.invalidate();
|
||||
|
||||
assertRenders(view, BASE_PATH + "renderMonthly.png");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRender_withTransparentBackground() throws Throwable
|
||||
{
|
||||
view.setIsTransparencyEnabled(true);
|
||||
assertRenders(view, BASE_PATH + "renderTransparent.png");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRender_withYearlyBucket() throws Throwable
|
||||
{
|
||||
ScoreCardState model = ScoreCardPresenter.Companion.buildState(habit, prefs.getFirstWeekdayInt(), 4);
|
||||
view.setScores(model.getScores());
|
||||
view.setBucketSize(model.getBucketSize());
|
||||
view.invalidate();
|
||||
|
||||
assertRenders(view, BASE_PATH + "renderYearly.png");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
* 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.activities.common.views;
|
||||
|
||||
import androidx.test.filters.*;
|
||||
import androidx.test.runner.*;
|
||||
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
|
||||
import org.isoron.uhabits.*;
|
||||
import org.isoron.uhabits.core.models.*;
|
||||
import org.isoron.uhabits.utils.*;
|
||||
import org.junit.*;
|
||||
import org.junit.runner.*;
|
||||
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
@MediumTest
|
||||
public class StreakChartTest extends BaseViewTest
|
||||
{
|
||||
private static final String BASE_PATH = "common/StreakChart/";
|
||||
|
||||
private StreakChart view;
|
||||
|
||||
@Override
|
||||
@Before
|
||||
public void setUp()
|
||||
{
|
||||
super.setUp();
|
||||
|
||||
fixtures.purgeHabits(habitList);
|
||||
Habit habit = fixtures.createLongHabit();
|
||||
|
||||
view = new StreakChart(targetContext);
|
||||
view.setColor(PaletteUtilsKt.toFixedAndroidColor(habit.getColor()));
|
||||
view.setStreaks(habit.getStreaks().getBest(5));
|
||||
measureView(view, dpToPixels(300), dpToPixels(100));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRender() throws Throwable
|
||||
{
|
||||
assertRenders(view, BASE_PATH + "render.png");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRender_withSmallSize() throws Throwable
|
||||
{
|
||||
measureView(view, dpToPixels(100), dpToPixels(100));
|
||||
assertRenders(view, BASE_PATH + "renderSmallSize.png");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRender_withTransparentBackground() throws Throwable
|
||||
{
|
||||
view.setIsBackgroundTransparent(true);
|
||||
assertRenders(view, BASE_PATH + "renderTransparent.png");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,100 @@
|
||||
/*
|
||||
* 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.activities.habits.list.views
|
||||
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||
import androidx.test.filters.MediumTest
|
||||
import org.isoron.uhabits.BaseViewTest
|
||||
import org.isoron.uhabits.core.models.Entry
|
||||
import org.isoron.uhabits.utils.PaletteUtils
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
|
||||
@RunWith(AndroidJUnit4::class)
|
||||
@MediumTest
|
||||
class EntryButtonViewTest : BaseViewTest() {
|
||||
|
||||
private val PATH = "habits/list/CheckmarkButtonView"
|
||||
lateinit var view: CheckmarkButtonView
|
||||
|
||||
var toggled = false
|
||||
|
||||
@Before
|
||||
override fun setUp() {
|
||||
super.setUp()
|
||||
view = component.getEntryButtonViewFactory().create().apply {
|
||||
value = Entry.NO
|
||||
color = PaletteUtils.getAndroidTestColor(5)
|
||||
onToggle = { toggled = true }
|
||||
}
|
||||
measureView(view, dpToPixels(48), dpToPixels(48))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testRender_explicitCheck() {
|
||||
view.value = Entry.YES_MANUAL
|
||||
assertRendersCheckedExplicitly()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testRender_implicitCheck() {
|
||||
view.value = Entry.YES_AUTO
|
||||
assertRendersCheckedImplicitly()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testRender_unchecked() {
|
||||
view.value = Entry.NO
|
||||
assertRendersUnchecked()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testClick_withShortToggleDisabled() {
|
||||
prefs.isShortToggleEnabled = false
|
||||
view.performClick()
|
||||
assertFalse(toggled)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testClick_withShortToggleEnabled() {
|
||||
prefs.isShortToggleEnabled = true
|
||||
view.performClick()
|
||||
assertTrue(toggled)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testLongClick() {
|
||||
view.performLongClick()
|
||||
assertTrue(toggled)
|
||||
}
|
||||
|
||||
private fun assertRendersCheckedExplicitly() {
|
||||
assertRenders(view, "$PATH/render_explicit_check.png")
|
||||
}
|
||||
|
||||
private fun assertRendersCheckedImplicitly() {
|
||||
assertRenders(view, "$PATH/render_implicit_check.png")
|
||||
}
|
||||
|
||||
private fun assertRendersUnchecked() {
|
||||
assertRenders(view, "$PATH/render_unchecked.png")
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,119 @@
|
||||
/*
|
||||
* 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.activities.habits.list.views
|
||||
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||
import androidx.test.filters.MediumTest
|
||||
import org.hamcrest.CoreMatchers.equalTo
|
||||
import org.hamcrest.MatcherAssert.assertThat
|
||||
import org.isoron.uhabits.BaseViewTest
|
||||
import org.isoron.uhabits.core.models.Entry.Companion.NO
|
||||
import org.isoron.uhabits.core.models.Entry.Companion.YES_AUTO
|
||||
import org.isoron.uhabits.core.models.Entry.Companion.YES_MANUAL
|
||||
import org.isoron.uhabits.core.models.Timestamp
|
||||
import org.isoron.uhabits.utils.PaletteUtils
|
||||
import org.junit.After
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
|
||||
@RunWith(AndroidJUnit4::class)
|
||||
@MediumTest
|
||||
class EntryPanelViewTest : BaseViewTest() {
|
||||
|
||||
private val PATH = "habits/list/CheckmarkPanelView"
|
||||
private lateinit var view: CheckmarkPanelView
|
||||
|
||||
@Before
|
||||
override fun setUp() {
|
||||
super.setUp()
|
||||
prefs.isCheckmarkSequenceReversed = false
|
||||
|
||||
val checkmarks = intArrayOf(
|
||||
YES_MANUAL,
|
||||
YES_MANUAL,
|
||||
YES_AUTO,
|
||||
NO,
|
||||
NO,
|
||||
NO,
|
||||
YES_MANUAL
|
||||
)
|
||||
|
||||
view = component.getCheckmarkPanelViewFactory().create().apply {
|
||||
values = checkmarks
|
||||
buttonCount = 4
|
||||
color = PaletteUtils.getAndroidTestColor(7)
|
||||
}
|
||||
view.onAttachedToWindow()
|
||||
measureView(view, dpToPixels(200), dpToPixels(200))
|
||||
}
|
||||
|
||||
@After
|
||||
public override fun tearDown() {
|
||||
super.tearDown()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testRender() {
|
||||
assertRenders(view, "$PATH/render.png")
|
||||
}
|
||||
|
||||
// // Flaky test
|
||||
// @Test
|
||||
// fun testRender_withDifferentColor() {
|
||||
// view.color = PaletteUtils.getAndroidTestColor(1)
|
||||
// assertRenders(view, "$PATH/render_different_color.png")
|
||||
// }
|
||||
|
||||
// // Flaky test
|
||||
// @Test
|
||||
// fun testRender_Reversed() {
|
||||
// prefs.isCheckmarkSequenceReversed = true
|
||||
// assertRenders(view, "$PATH/render_reversed.png")
|
||||
// }
|
||||
|
||||
// // Flaky test
|
||||
// @Test
|
||||
// fun testRender_withOffset() {
|
||||
// view.dataOffset = 3
|
||||
// assertRenders(view, "$PATH/render_offset.png")
|
||||
// }
|
||||
|
||||
@Test
|
||||
fun testToggle() {
|
||||
val timestamps = mutableListOf<Timestamp>()
|
||||
view.onToggle = { t, _ -> timestamps.add(t) }
|
||||
view.buttons[0].performLongClick()
|
||||
view.buttons[2].performLongClick()
|
||||
view.buttons[3].performLongClick()
|
||||
assertThat(timestamps, equalTo(listOf(day(0), day(2), day(3))))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testToggle_withOffset() {
|
||||
val timestamps = mutableListOf<Timestamp>()
|
||||
view.dataOffset = 3
|
||||
view.onToggle = { t, _ -> timestamps += t }
|
||||
view.buttons[0].performLongClick()
|
||||
view.buttons[2].performLongClick()
|
||||
view.buttons[3].performLongClick()
|
||||
assertThat(timestamps, equalTo(listOf(day(3), day(5), day(6))))
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,103 @@
|
||||
/*
|
||||
* 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.activities.habits.list.views
|
||||
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||
import androidx.test.filters.MediumTest
|
||||
import org.isoron.uhabits.BaseViewTest
|
||||
import org.isoron.uhabits.R
|
||||
import org.isoron.uhabits.core.models.Habit
|
||||
import org.isoron.uhabits.core.models.PaletteColor
|
||||
import org.isoron.uhabits.core.models.Timestamp
|
||||
import org.isoron.uhabits.core.utils.DateUtils
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
|
||||
@RunWith(AndroidJUnit4::class)
|
||||
@MediumTest
|
||||
class HabitCardViewTest : BaseViewTest() {
|
||||
|
||||
val PATH = "habits/list/HabitCardView"
|
||||
private lateinit var view: HabitCardView
|
||||
private lateinit var habit1: Habit
|
||||
private lateinit var habit2: Habit
|
||||
private lateinit var today: Timestamp
|
||||
|
||||
override fun setUp() {
|
||||
super.setUp()
|
||||
setTheme(R.style.AppBaseTheme)
|
||||
|
||||
habit1 = fixtures.createLongHabit()
|
||||
habit2 = fixtures.createLongNumericalHabit()
|
||||
today = DateUtils.getTodayWithOffset()
|
||||
|
||||
val entries = habit1
|
||||
.computedEntries
|
||||
.getByInterval(today.minus(300), today)
|
||||
.map { it.value }.toIntArray()
|
||||
|
||||
view = component.getHabitCardViewFactory().create().apply {
|
||||
habit = habit1
|
||||
values = entries
|
||||
score = habit1.scores.get(today).value
|
||||
isSelected = false
|
||||
buttonCount = 5
|
||||
}
|
||||
latch.countDown()
|
||||
|
||||
latch.await()
|
||||
measureView(view, dpToPixels(400), dpToPixels(50))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testRender() {
|
||||
assertRenders(view, "$PATH/render.png")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testRender_selected() {
|
||||
view.isSelected = true
|
||||
measureView(view, dpToPixels(400), dpToPixels(50))
|
||||
assertRenders(view, "$PATH/render_selected.png")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testRender_numerical() {
|
||||
val entries = habit2
|
||||
.computedEntries
|
||||
.getByInterval(today.minus(300), today)
|
||||
.map { it.value }.toIntArray()
|
||||
|
||||
view.apply {
|
||||
habit = habit2
|
||||
values = entries
|
||||
}
|
||||
assertRenders(view, "$PATH/render_numerical.png")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testChangeModel() {
|
||||
habit1.name = "Wake up early"
|
||||
habit1.color = PaletteColor(2)
|
||||
habit1.observable.notifyListeners()
|
||||
Thread.sleep(500)
|
||||
assertRenders(view, "$PATH/render_changed.png")
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
/*
|
||||
* 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.activities.habits.list.views;
|
||||
|
||||
import androidx.test.filters.*;
|
||||
import androidx.test.runner.*;
|
||||
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
|
||||
import org.isoron.uhabits.*;
|
||||
import org.isoron.uhabits.core.preferences.*;
|
||||
import org.isoron.uhabits.core.utils.*;
|
||||
import org.junit.*;
|
||||
import org.junit.runner.*;
|
||||
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
@MediumTest
|
||||
public class HeaderViewTest extends BaseViewTest
|
||||
{
|
||||
public static final String PATH = "habits/list/HeaderView/";
|
||||
|
||||
private HeaderView view;
|
||||
|
||||
private Preferences prefs;
|
||||
|
||||
private MidnightTimer midnightTimer;
|
||||
|
||||
@Override
|
||||
@Before
|
||||
public void setUp()
|
||||
{
|
||||
super.setUp();
|
||||
prefs = mock(Preferences.class);
|
||||
midnightTimer = mock(MidnightTimer.class);
|
||||
view = new HeaderView(targetContext, prefs, midnightTimer);
|
||||
view.setButtonCount(5);
|
||||
measureView(view, dpToPixels(600), dpToPixels(48));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRender() throws Exception
|
||||
{
|
||||
when(prefs.isCheckmarkSequenceReversed()).thenReturn(false);
|
||||
|
||||
assertRenders(view, PATH + "render.png");
|
||||
|
||||
verify(prefs).isCheckmarkSequenceReversed();
|
||||
verifyNoMoreInteractions(prefs);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRender_reverse() throws Exception
|
||||
{
|
||||
when(prefs.isCheckmarkSequenceReversed()).thenReturn(true);
|
||||
|
||||
assertRenders(view, PATH + "render_reverse.png");
|
||||
|
||||
verify(prefs).isCheckmarkSequenceReversed();
|
||||
verifyNoMoreInteractions(prefs);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
/*
|
||||
* 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.activities.habits.list.views;
|
||||
|
||||
import androidx.test.filters.*;
|
||||
import androidx.test.runner.*;
|
||||
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
|
||||
import org.isoron.uhabits.*;
|
||||
import org.isoron.uhabits.core.ui.screens.habits.list.*;
|
||||
import org.junit.*;
|
||||
import org.junit.runner.*;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.*;
|
||||
import static org.hamcrest.MatcherAssert.*;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
@MediumTest
|
||||
public class HintViewTest extends BaseViewTest
|
||||
{
|
||||
public static final String PATH = "habits/list/HintView/";
|
||||
|
||||
private HintView view;
|
||||
|
||||
private HintList list;
|
||||
|
||||
@Before
|
||||
@Override
|
||||
public void setUp()
|
||||
{
|
||||
super.setUp();
|
||||
|
||||
list = mock(HintList.class);
|
||||
view = new HintView(targetContext, list);
|
||||
measureView(view, 400, 200);
|
||||
|
||||
String text =
|
||||
"Lorem ipsum dolor sit amet, consectetur adipiscing elit.";
|
||||
|
||||
when(list.shouldShow()).thenReturn(true);
|
||||
when(list.pop()).thenReturn(text);
|
||||
|
||||
view.showNext();
|
||||
skipAnimation(view);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRender() throws Exception
|
||||
{
|
||||
assertRenders(view, PATH + "render.png");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testClick() throws Exception
|
||||
{
|
||||
assertThat(view.getAlpha(), equalTo(1f));
|
||||
view.performClick();
|
||||
skipAnimation(view);
|
||||
assertThat(view.getAlpha(), equalTo(0f));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,107 @@
|
||||
/*
|
||||
* 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.activities.habits.list.views
|
||||
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||
import androidx.test.filters.MediumTest
|
||||
import org.hamcrest.CoreMatchers.equalTo
|
||||
import org.hamcrest.MatcherAssert.assertThat
|
||||
import org.isoron.uhabits.BaseViewTest
|
||||
import org.isoron.uhabits.utils.PaletteUtils
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
|
||||
@RunWith(AndroidJUnit4::class)
|
||||
@MediumTest
|
||||
class NumberButtonViewTest : BaseViewTest() {
|
||||
|
||||
private val PATH = "habits/list/NumberButtonView"
|
||||
private lateinit var view: NumberButtonView
|
||||
var edited = false
|
||||
|
||||
@Before
|
||||
override fun setUp() {
|
||||
super.setUp()
|
||||
view = component.getNumberButtonViewFactory().create().apply {
|
||||
units = "steps"
|
||||
threshold = 100.0
|
||||
color = PaletteUtils.getAndroidTestColor(8)
|
||||
onEdit = { edited = true }
|
||||
}
|
||||
measureView(view, dpToPixels(48), dpToPixels(48))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testFormatValue() {
|
||||
assertThat(0.1235.toShortString(), equalTo("0.12"))
|
||||
assertThat(0.1000.toShortString(), equalTo("0.1"))
|
||||
assertThat(5.0.toShortString(), equalTo("5"))
|
||||
assertThat(5.25.toShortString(), equalTo("5.25"))
|
||||
assertThat(12.3456.toShortString(), equalTo("12.3"))
|
||||
assertThat(123.123.toShortString(), equalTo("123"))
|
||||
assertThat(321.2.toShortString(), equalTo("321"))
|
||||
assertThat(4321.2.toShortString(), equalTo("4.3k"))
|
||||
assertThat(54321.2.toShortString(), equalTo("54.3k"))
|
||||
assertThat(654321.2.toShortString(), equalTo("654k"))
|
||||
assertThat(7654321.2.toShortString(), equalTo("7.7M"))
|
||||
assertThat(87654321.2.toShortString(), equalTo("87.7M"))
|
||||
assertThat(987654321.2.toShortString(), equalTo("988M"))
|
||||
assertThat(1987654321.2.toShortString(), equalTo("2.0G"))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testRender_aboveThreshold() {
|
||||
view.value = 500.0
|
||||
assertRenders(view, "$PATH/render_above.png")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testRender_belowThreshold() {
|
||||
view.value = 99.0
|
||||
assertRenders(view, "$PATH/render_below.png")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testRender_zero() {
|
||||
view.value = 0.0
|
||||
assertRenders(view, "$PATH/render_zero.png")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testClick_shortToggleDisabled() {
|
||||
prefs.isShortToggleEnabled = false
|
||||
view.performClick()
|
||||
assertFalse(edited)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testClick_shortToggleEnabled() {
|
||||
prefs.isShortToggleEnabled = true
|
||||
view.performClick()
|
||||
assertTrue(edited)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testLongClick() {
|
||||
view.performLongClick()
|
||||
assertTrue(edited)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,117 @@
|
||||
/*
|
||||
* 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.activities.habits.list.views
|
||||
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||
import androidx.test.filters.MediumTest
|
||||
import org.hamcrest.CoreMatchers.equalTo
|
||||
import org.hamcrest.MatcherAssert.assertThat
|
||||
import org.isoron.uhabits.BaseViewTest
|
||||
import org.isoron.uhabits.core.models.Timestamp
|
||||
import org.isoron.uhabits.utils.PaletteUtils
|
||||
import org.junit.After
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
|
||||
@RunWith(AndroidJUnit4::class)
|
||||
@MediumTest
|
||||
class NumberPanelViewTest : BaseViewTest() {
|
||||
|
||||
private val PATH = "habits/list/NumberPanelView"
|
||||
private lateinit var view: NumberPanelView
|
||||
|
||||
@Before
|
||||
override fun setUp() {
|
||||
super.setUp()
|
||||
prefs.isCheckmarkSequenceReversed = false
|
||||
|
||||
val checkmarks = doubleArrayOf(
|
||||
1400.0,
|
||||
5300.0,
|
||||
0.0,
|
||||
14600.0,
|
||||
2500.0,
|
||||
45000.0
|
||||
)
|
||||
|
||||
view = component.getNumberPanelViewFactory().create().apply {
|
||||
values = checkmarks
|
||||
buttonCount = 4
|
||||
color = PaletteUtils.getAndroidTestColor(7)
|
||||
units = "steps"
|
||||
threshold = 5000.0
|
||||
}
|
||||
view.onAttachedToWindow()
|
||||
measureView(view, dpToPixels(200), dpToPixels(200))
|
||||
}
|
||||
|
||||
@After
|
||||
public override fun tearDown() {
|
||||
view.onDetachedFromWindow()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testRender() {
|
||||
assertRenders(view, "$PATH/render.png")
|
||||
}
|
||||
|
||||
// // Flaky test
|
||||
// @Test
|
||||
// fun testRender_withDifferentColor() {
|
||||
// view.color = PaletteUtils.getAndroidTestColor(1)
|
||||
// assertRenders(view, "$PATH/render_different_color.png")
|
||||
// }
|
||||
|
||||
// // Flaky test
|
||||
// @Test
|
||||
// fun testRender_Reversed() {
|
||||
// prefs.isCheckmarkSequenceReversed = true
|
||||
// assertRenders(view, "$PATH/render_reversed.png")
|
||||
// }
|
||||
|
||||
// // Flaky test
|
||||
// @Test
|
||||
// fun testRender_withOffset() {
|
||||
// view.dataOffset = 3
|
||||
// assertRenders(view, "$PATH/render_offset.png")
|
||||
// }
|
||||
|
||||
@Test
|
||||
fun testEdit() {
|
||||
val timestamps = mutableListOf<Timestamp>()
|
||||
view.onEdit = { timestamps.plusAssign(it) }
|
||||
view.buttons[0].performLongClick()
|
||||
view.buttons[2].performLongClick()
|
||||
view.buttons[3].performLongClick()
|
||||
assertThat(timestamps, equalTo(listOf(day(0), day(2), day(3))))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testEdit_withOffset() {
|
||||
val timestamps = mutableListOf<Timestamp>()
|
||||
view.dataOffset = 3
|
||||
view.onEdit = { timestamps += it }
|
||||
view.buttons[0].performLongClick()
|
||||
view.buttons[2].performLongClick()
|
||||
view.buttons[3].performLongClick()
|
||||
assertThat(timestamps, equalTo(listOf(day(3), day(5), day(6))))
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* 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.activities.habits.show.views
|
||||
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||
import androidx.test.filters.MediumTest
|
||||
import org.isoron.uhabits.BaseViewTest
|
||||
import org.isoron.uhabits.R
|
||||
import org.isoron.uhabits.core.ui.screens.habits.show.views.FrequencyCardPresenter
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
|
||||
@RunWith(AndroidJUnit4::class)
|
||||
@MediumTest
|
||||
class FrequencyCardViewTest : BaseViewTest() {
|
||||
val PATH = "habits/show/FrequencyCard/"
|
||||
private lateinit var view: FrequencyCardView
|
||||
|
||||
@Before
|
||||
override fun setUp() {
|
||||
super.setUp()
|
||||
val habit = fixtures.createLongHabit()
|
||||
view = LayoutInflater
|
||||
.from(targetContext)
|
||||
.inflate(R.layout.show_habit, null)
|
||||
.findViewById<View>(R.id.frequencyCard) as FrequencyCardView
|
||||
view.setState(FrequencyCardPresenter.buildState(habit = habit, firstWeekday = 0))
|
||||
measureView(view, 800f, 600f)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testRender() {
|
||||
assertRenders(view, PATH + "render.png")
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* 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.activities.habits.show.views
|
||||
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||
import androidx.test.filters.MediumTest
|
||||
import org.isoron.platform.time.DayOfWeek.SUNDAY
|
||||
import org.isoron.uhabits.BaseViewTest
|
||||
import org.isoron.uhabits.R
|
||||
import org.isoron.uhabits.core.ui.screens.habits.show.views.HistoryCardPresenter
|
||||
import org.isoron.uhabits.core.ui.views.LightTheme
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
|
||||
@RunWith(AndroidJUnit4::class)
|
||||
@MediumTest
|
||||
class HistoryCardViewTest : BaseViewTest() {
|
||||
private lateinit var view: HistoryCardView
|
||||
val PATH = "habits/show/HistoryCard/"
|
||||
|
||||
@Before
|
||||
override fun setUp() {
|
||||
super.setUp()
|
||||
val habit = fixtures.createLongHabit()
|
||||
view = LayoutInflater
|
||||
.from(targetContext)
|
||||
.inflate(R.layout.show_habit, null)
|
||||
.findViewById<View>(R.id.historyCard) as HistoryCardView
|
||||
view.setState(
|
||||
HistoryCardPresenter.buildState(
|
||||
habit = habit,
|
||||
firstWeekday = SUNDAY,
|
||||
theme = LightTheme(),
|
||||
)
|
||||
)
|
||||
measureView(view, 800f, 600f)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testRender() {
|
||||
assertRenders(view, PATH + "render.png")
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* 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.activities.habits.show.views
|
||||
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View.GONE
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||
import androidx.test.filters.MediumTest
|
||||
import org.hamcrest.Matchers.equalTo
|
||||
import org.isoron.uhabits.BaseViewTest
|
||||
import org.isoron.uhabits.R
|
||||
import org.isoron.uhabits.core.ui.screens.habits.show.views.NotesCardState
|
||||
import org.junit.Assert.assertThat
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
|
||||
@RunWith(AndroidJUnit4::class)
|
||||
@MediumTest
|
||||
class NotesCardViewTest : BaseViewTest() {
|
||||
val PATH = "habits/show/NotesCard"
|
||||
private lateinit var view: NotesCardView
|
||||
|
||||
@Before
|
||||
override fun setUp() {
|
||||
super.setUp()
|
||||
view = LayoutInflater
|
||||
.from(targetContext)
|
||||
.inflate(R.layout.show_habit, null)
|
||||
.findViewById(R.id.notesCard)
|
||||
view.setState(NotesCardState(description = "This is a test description"))
|
||||
measureView(view, 800f, 200f)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testRender() {
|
||||
assertRenders(view, "$PATH/render.png")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testRenderEmptyDescription() {
|
||||
view.setState(NotesCardState(description = ""))
|
||||
assertThat(view.visibility, equalTo(GONE))
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* 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.activities.habits.show.views
|
||||
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||
import androidx.test.filters.MediumTest
|
||||
import org.isoron.uhabits.BaseViewTest
|
||||
import org.isoron.uhabits.R
|
||||
import org.isoron.uhabits.core.models.PaletteColor
|
||||
import org.isoron.uhabits.core.ui.screens.habits.show.views.OverviewCardState
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
|
||||
@RunWith(AndroidJUnit4::class)
|
||||
@MediumTest
|
||||
class OverviewCardViewTest : BaseViewTest() {
|
||||
val PATH = "habits/show/OverviewCard/"
|
||||
private lateinit var view: OverviewCardView
|
||||
|
||||
@Before
|
||||
override fun setUp() {
|
||||
super.setUp()
|
||||
view = LayoutInflater
|
||||
.from(targetContext)
|
||||
.inflate(R.layout.show_habit, null)
|
||||
.findViewById<View>(R.id.overviewCard) as OverviewCardView
|
||||
view.setState(
|
||||
OverviewCardState(
|
||||
scoreToday = 0.74f,
|
||||
scoreMonthDiff = 0.23f,
|
||||
scoreYearDiff = 0.74f,
|
||||
totalCount = 44,
|
||||
color = PaletteColor(7),
|
||||
)
|
||||
)
|
||||
measureView(view, 800f, 300f)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testRender() {
|
||||
assertRenders(view, PATH + "render.png")
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
* 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.activities.habits.show.views
|
||||
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||
import androidx.test.filters.MediumTest
|
||||
import org.isoron.uhabits.BaseViewTest
|
||||
import org.isoron.uhabits.R
|
||||
import org.isoron.uhabits.core.ui.screens.habits.show.views.ScoreCardPresenter
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
|
||||
@RunWith(AndroidJUnit4::class)
|
||||
@MediumTest
|
||||
class ScoreCardViewTest : BaseViewTest() {
|
||||
val PATH = "habits/show/ScoreCard/"
|
||||
private lateinit var view: ScoreCardView
|
||||
|
||||
@Before
|
||||
override fun setUp() {
|
||||
super.setUp()
|
||||
val habit = fixtures.createLongHabit()
|
||||
view = LayoutInflater
|
||||
.from(targetContext)
|
||||
.inflate(R.layout.show_habit, null)
|
||||
.findViewById<View>(R.id.scoreCard) as ScoreCardView
|
||||
view.setState(
|
||||
ScoreCardPresenter.buildState(
|
||||
habit = habit,
|
||||
firstWeekday = 0,
|
||||
spinnerPosition = 0,
|
||||
)
|
||||
)
|
||||
measureView(view, 800f, 600f)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testRender() {
|
||||
assertRenders(view, PATH + "render.png")
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* 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.activities.habits.show.views
|
||||
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||
import androidx.test.filters.MediumTest
|
||||
import org.isoron.uhabits.BaseViewTest
|
||||
import org.isoron.uhabits.R
|
||||
import org.isoron.uhabits.core.ui.screens.habits.show.views.StreakCardState
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
|
||||
@RunWith(AndroidJUnit4::class)
|
||||
@MediumTest
|
||||
class StreakCardViewTest : BaseViewTest() {
|
||||
val PATH = "habits/show/StreakCard/"
|
||||
private lateinit var view: StreakCardView
|
||||
|
||||
@Before
|
||||
override fun setUp() {
|
||||
super.setUp()
|
||||
val habit = fixtures.createLongHabit()
|
||||
view = LayoutInflater
|
||||
.from(targetContext)
|
||||
.inflate(R.layout.show_habit, null)
|
||||
.findViewById<View>(R.id.streakCard) as StreakCardView
|
||||
view.setState(
|
||||
StreakCardState(
|
||||
bestStreaks = habit.streaks.getBest(10),
|
||||
color = habit.color,
|
||||
)
|
||||
)
|
||||
measureView(view, 800f, 600f)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testRender() {
|
||||
assertRenders(view, PATH + "render.png")
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
* 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.activities.habits.show.views
|
||||
|
||||
import android.view.LayoutInflater
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||
import androidx.test.filters.MediumTest
|
||||
import org.isoron.uhabits.BaseViewTest
|
||||
import org.isoron.uhabits.R
|
||||
import org.isoron.uhabits.core.models.Frequency
|
||||
import org.isoron.uhabits.core.models.PaletteColor
|
||||
import org.isoron.uhabits.core.models.Reminder
|
||||
import org.isoron.uhabits.core.models.WeekdayList.EVERY_DAY
|
||||
import org.isoron.uhabits.core.ui.screens.habits.show.views.SubtitleCardState
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
|
||||
@RunWith(AndroidJUnit4::class)
|
||||
@MediumTest
|
||||
class SubtitleCardViewTest : BaseViewTest() {
|
||||
val PATH = "habits/show/SubtitleCard/"
|
||||
private lateinit var view: SubtitleCardView
|
||||
|
||||
@Before
|
||||
override fun setUp() {
|
||||
super.setUp()
|
||||
view = LayoutInflater
|
||||
.from(targetContext)
|
||||
.inflate(R.layout.show_habit, null)
|
||||
.findViewById(R.id.subtitleCard)
|
||||
view.setState(
|
||||
SubtitleCardState(
|
||||
color = PaletteColor(7),
|
||||
frequency = Frequency(3, 7),
|
||||
isNumerical = false,
|
||||
question = "Did you meditate this morning?",
|
||||
reminder = Reminder(8, 30, EVERY_DAY),
|
||||
unit = "",
|
||||
targetValue = 0.0,
|
||||
)
|
||||
)
|
||||
measureView(view, 800f, 200f)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testRender() {
|
||||
assertRenders(view, PATH + "render.png")
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* Copyright (C) 2015-2017 Á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.database;
|
||||
|
||||
import android.database.sqlite.*;
|
||||
|
||||
import org.isoron.uhabits.*;
|
||||
import org.isoron.uhabits.core.database.*;
|
||||
import org.junit.*;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import static org.hamcrest.MatcherAssert.*;
|
||||
import static org.hamcrest.core.IsEqual.*;
|
||||
|
||||
|
||||
public class AndroidDatabaseTest extends BaseAndroidTest
|
||||
{
|
||||
private AndroidDatabase db;
|
||||
|
||||
@Override
|
||||
public void setUp()
|
||||
{
|
||||
super.setUp();
|
||||
db = new AndroidDatabase(SQLiteDatabase.create(null), null);
|
||||
db.execute("create table test(color int, name string)");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInsert() throws Exception
|
||||
{
|
||||
HashMap<String, Object> map = new HashMap<>();
|
||||
map.put("name", "asd");
|
||||
map.put("color", null);
|
||||
db.insert("test", map);
|
||||
|
||||
Cursor c = db.query("select * from test");
|
||||
c.moveToNext();
|
||||
assertNull(c.getInt(0));
|
||||
assertThat(c.getString(1), equalTo("asd"));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
/*
|
||||
* Copyright (C) 2016-2020 Á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.database
|
||||
|
||||
import org.isoron.uhabits.AndroidDirFinder
|
||||
import org.isoron.uhabits.BaseAndroidTest
|
||||
import org.isoron.uhabits.core.utils.DateUtils
|
||||
import org.junit.Test
|
||||
import java.io.File
|
||||
import java.io.FileOutputStream
|
||||
|
||||
class AutoBackupTest : BaseAndroidTest() {
|
||||
@Test
|
||||
fun testRun() {
|
||||
DateUtils.setFixedLocalTime(40 * DateUtils.DAY_LENGTH)
|
||||
val basedir = AndroidDirFinder(targetContext).getFilesDir("Backups")!!
|
||||
createTestFiles(basedir, 30)
|
||||
|
||||
val autoBackup = AutoBackup(targetContext)
|
||||
autoBackup.run(keep = 5)
|
||||
|
||||
for (k in 1..25) assertDoesNotExist("${basedir.path}/test-$k.txt")
|
||||
for (k in 26..30) assertExists("${basedir.path}/test-$k.txt")
|
||||
assertExists("${basedir.path}/Loop Habits Backup 1970-02-10 000000.db")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testRunWithEmptyDir() {
|
||||
val basedir = AndroidDirFinder(targetContext).getFilesDir("Backups")!!
|
||||
removeAllFiles(basedir)
|
||||
basedir.delete()
|
||||
|
||||
// Should not crash
|
||||
val autoBackup = AutoBackup(targetContext)
|
||||
autoBackup.run()
|
||||
}
|
||||
|
||||
private fun assertExists(path: String) {
|
||||
assertTrue("File $path should exist", File(path).exists())
|
||||
}
|
||||
|
||||
private fun assertDoesNotExist(path: String) {
|
||||
assertFalse("File $path should not exist", File(path).exists())
|
||||
}
|
||||
|
||||
private fun createTestFiles(basedir: File, nfiles: Int) {
|
||||
removeAllFiles(basedir)
|
||||
for (k in 1..nfiles) {
|
||||
touch("${basedir.path}/test-$k.txt", DateUtils.DAY_LENGTH * k)
|
||||
}
|
||||
}
|
||||
|
||||
private fun touch(path: String, time: Long) {
|
||||
val file = File(path)
|
||||
FileOutputStream(file).close()
|
||||
file.setLastModified(time)
|
||||
}
|
||||
|
||||
private fun removeAllFiles(dir: File) {
|
||||
dir.list().forEach { path ->
|
||||
val file = File("${dir.path}/$path")
|
||||
assertTrue(file.delete())
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,129 @@
|
||||
/*
|
||||
* Copyright (C) 2016-2020 Á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.intents
|
||||
|
||||
import android.content.ContentUris.parseId
|
||||
import androidx.test.filters.MediumTest
|
||||
import org.hamcrest.Matchers.equalTo
|
||||
import org.isoron.uhabits.BaseAndroidTest
|
||||
import org.isoron.uhabits.core.reminders.ReminderScheduler.SchedulerResult.OK
|
||||
import org.isoron.uhabits.receivers.ReminderReceiver
|
||||
import org.isoron.uhabits.receivers.WidgetReceiver
|
||||
import org.junit.After
|
||||
import org.junit.Assert.assertThat
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
import java.util.Calendar.DAY_OF_MONTH
|
||||
import java.util.Calendar.DECEMBER
|
||||
import java.util.Calendar.HOUR_OF_DAY
|
||||
import java.util.Calendar.JUNE
|
||||
import java.util.Calendar.MAY
|
||||
import java.util.Calendar.MINUTE
|
||||
import java.util.Calendar.MONTH
|
||||
import java.util.Calendar.YEAR
|
||||
import java.util.GregorianCalendar
|
||||
import java.util.TimeZone
|
||||
|
||||
class IntentSchedulerTest : BaseAndroidTest() {
|
||||
|
||||
@Before
|
||||
override fun setUp() {
|
||||
super.setUp()
|
||||
saveSystemTime()
|
||||
}
|
||||
|
||||
@After
|
||||
override fun tearDown() {
|
||||
restoreSystemTime()
|
||||
super.tearDown()
|
||||
}
|
||||
|
||||
@Test
|
||||
@MediumTest
|
||||
@Throws(Exception::class)
|
||||
fun testSetSystemTime() {
|
||||
setSystemTime("America/Chicago", 2020, JUNE, 1, 12, 40)
|
||||
var cal = GregorianCalendar()
|
||||
assertThat(cal.timeZone, equalTo(TimeZone.getTimeZone("America/Chicago")))
|
||||
assertThat(cal[YEAR], equalTo(2020))
|
||||
assertThat(cal[MONTH], equalTo(JUNE))
|
||||
assertThat(cal[DAY_OF_MONTH], equalTo(1))
|
||||
assertThat(cal[HOUR_OF_DAY], equalTo(12))
|
||||
assertThat(cal[MINUTE], equalTo(40))
|
||||
|
||||
setSystemTime("Europe/Paris", 2019, MAY, 15, 6, 30)
|
||||
cal = GregorianCalendar()
|
||||
assertThat(cal.timeZone, equalTo(TimeZone.getTimeZone("Europe/Paris")))
|
||||
assertThat(cal[YEAR], equalTo(2019))
|
||||
assertThat(cal[MONTH], equalTo(MAY))
|
||||
assertThat(cal[DAY_OF_MONTH], equalTo(15))
|
||||
assertThat(cal[HOUR_OF_DAY], equalTo(6))
|
||||
assertThat(cal[MINUTE], equalTo(30))
|
||||
|
||||
setSystemTime("Asia/Tokyo", 2021, DECEMBER, 20, 18, 0)
|
||||
cal = GregorianCalendar()
|
||||
assertThat(cal.timeZone, equalTo(TimeZone.getTimeZone("Asia/Tokyo")))
|
||||
assertThat(cal[YEAR], equalTo(2021))
|
||||
assertThat(cal[MONTH], equalTo(DECEMBER))
|
||||
assertThat(cal[DAY_OF_MONTH], equalTo(20))
|
||||
assertThat(cal[HOUR_OF_DAY], equalTo(18))
|
||||
assertThat(cal[MINUTE], equalTo(0))
|
||||
}
|
||||
|
||||
@Test
|
||||
@MediumTest
|
||||
fun testScheduleShowReminder() {
|
||||
for (h in habitList) h.reminder = null
|
||||
ReminderReceiver.clearLastReceivedIntent()
|
||||
|
||||
setSystemTime("America/Chicago", 2020, JUNE, 1, 12, 30)
|
||||
val reminderTime = 1591155900000 // 2020-06-02 22:45:00 (America/Chicago)
|
||||
|
||||
val habit = habitList.getByPosition(0)
|
||||
val scheduler = appComponent.intentScheduler
|
||||
assertThat(scheduler.scheduleShowReminder(reminderTime, habit, 0), equalTo(OK))
|
||||
|
||||
setSystemTime("America/Chicago", 2020, JUNE, 2, 22, 44)
|
||||
assertNull(ReminderReceiver.getLastReceivedIntent())
|
||||
|
||||
setSystemTime("America/Chicago", 2020, JUNE, 2, 22, 46)
|
||||
val intent = ReminderReceiver.getLastReceivedIntent()
|
||||
assertNotNull(intent)
|
||||
assertThat(parseId(intent.data!!), equalTo(habit.id))
|
||||
}
|
||||
|
||||
@Test
|
||||
@MediumTest
|
||||
fun testScheduleWidgetUpdate() {
|
||||
WidgetReceiver.clearLastReceivedIntent()
|
||||
|
||||
setSystemTime("America/Chicago", 2020, JUNE, 1, 12, 30)
|
||||
val updateTime = 1591155900000 // 2020-06-02 22:45:00 (America/Chicago)
|
||||
|
||||
val scheduler = appComponent.intentScheduler
|
||||
assertThat(scheduler.scheduleWidgetUpdate(updateTime), equalTo(OK))
|
||||
|
||||
setSystemTime("America/Chicago", 2020, JUNE, 2, 22, 44)
|
||||
assertNull(WidgetReceiver.getLastReceivedIntent())
|
||||
|
||||
setSystemTime("America/Chicago", 2020, JUNE, 2, 22, 46)
|
||||
val intent = WidgetReceiver.getLastReceivedIntent()
|
||||
assertNotNull(intent)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
* Copyright (C) 2017 Á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.performance;
|
||||
|
||||
import androidx.test.ext.junit.runners.*;
|
||||
import androidx.test.filters.*;
|
||||
|
||||
import org.isoron.uhabits.*;
|
||||
import org.isoron.uhabits.core.commands.*;
|
||||
import org.isoron.uhabits.core.database.*;
|
||||
import org.isoron.uhabits.core.models.*;
|
||||
import org.isoron.uhabits.core.models.sqlite.*;
|
||||
import org.junit.*;
|
||||
import org.junit.runner.*;
|
||||
|
||||
import static org.isoron.uhabits.core.models.Timestamp.*;
|
||||
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
@MediumTest
|
||||
public class PerformanceTest extends BaseAndroidTest
|
||||
{
|
||||
private Habit habit;
|
||||
|
||||
@Override
|
||||
public void setUp()
|
||||
{
|
||||
super.setUp();
|
||||
habit = fixtures.createLongHabit();
|
||||
}
|
||||
|
||||
@Ignore
|
||||
@Test(timeout = 5000)
|
||||
public void benchmarkCreateHabitCommand()
|
||||
{
|
||||
Database db = ((SQLModelFactory) modelFactory).getDatabase();
|
||||
db.beginTransaction();
|
||||
for (int i = 0; i < 1_000; i++)
|
||||
{
|
||||
Habit model = modelFactory.buildHabit();
|
||||
new CreateHabitCommand(modelFactory, habitList, model).run();
|
||||
}
|
||||
db.setTransactionSuccessful();
|
||||
db.endTransaction();
|
||||
}
|
||||
|
||||
@Ignore
|
||||
@Test(timeout = 5000)
|
||||
public void benchmarkCreateRepetitionCommand()
|
||||
{
|
||||
Database db = ((SQLModelFactory) modelFactory).getDatabase();
|
||||
db.beginTransaction();
|
||||
Habit habit = fixtures.createEmptyHabit();
|
||||
for (int i = 0; i < 5_000; i++)
|
||||
{
|
||||
Timestamp timestamp = new Timestamp(i * DAY_LENGTH);
|
||||
new CreateRepetitionCommand(habitList, habit, timestamp, 1).run();
|
||||
}
|
||||
db.setTransactionSuccessful();
|
||||
db.endTransaction();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
* Copyright (C) 2020 Á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.regression
|
||||
|
||||
import androidx.test.filters.LargeTest
|
||||
import org.isoron.uhabits.BaseUserInterfaceTest
|
||||
import org.isoron.uhabits.acceptance.steps.CommonSteps.Screen.EDIT_HABIT
|
||||
import org.isoron.uhabits.acceptance.steps.CommonSteps.Screen.LIST_HABITS
|
||||
import org.isoron.uhabits.acceptance.steps.CommonSteps.Screen.SELECT_HABIT_TYPE
|
||||
import org.isoron.uhabits.acceptance.steps.CommonSteps.clickText
|
||||
import org.isoron.uhabits.acceptance.steps.CommonSteps.launchApp
|
||||
import org.isoron.uhabits.acceptance.steps.CommonSteps.longClickText
|
||||
import org.isoron.uhabits.acceptance.steps.CommonSteps.verifyDisplaysText
|
||||
import org.isoron.uhabits.acceptance.steps.CommonSteps.verifyShowsScreen
|
||||
import org.isoron.uhabits.acceptance.steps.EditHabitSteps.clickSave
|
||||
import org.isoron.uhabits.acceptance.steps.EditHabitSteps.typeName
|
||||
import org.isoron.uhabits.acceptance.steps.ListHabitsSteps.MenuItem.ADD
|
||||
import org.isoron.uhabits.acceptance.steps.ListHabitsSteps.MenuItem.DELETE
|
||||
import org.isoron.uhabits.acceptance.steps.ListHabitsSteps.clickMenu
|
||||
import org.isoron.uhabits.acceptance.steps.ListHabitsSteps.longPressCheckmarks
|
||||
import org.junit.Test
|
||||
|
||||
@LargeTest
|
||||
class ListHabitsRegressionTest : BaseUserInterfaceTest() {
|
||||
/**
|
||||
* https://github.com/iSoron/uhabits/issues/539
|
||||
*/
|
||||
@Test
|
||||
@Throws(Exception::class)
|
||||
fun should_not_crash_after_deleting_then_adding_a_habit() {
|
||||
launchApp()
|
||||
verifyShowsScreen(LIST_HABITS)
|
||||
longClickText("Track time")
|
||||
clickMenu(DELETE)
|
||||
clickText("Yes")
|
||||
|
||||
clickMenu(ADD)
|
||||
verifyShowsScreen(SELECT_HABIT_TYPE)
|
||||
clickText("Yes or No")
|
||||
|
||||
verifyShowsScreen(EDIT_HABIT)
|
||||
typeName("Hello world")
|
||||
clickSave()
|
||||
|
||||
verifyDisplaysText("Hello world")
|
||||
longPressCheckmarks("Hello world", 3)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Copyright (C) 2020 Á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.regression
|
||||
|
||||
import androidx.test.filters.LargeTest
|
||||
import org.isoron.uhabits.BaseUserInterfaceTest
|
||||
import org.isoron.uhabits.acceptance.steps.CommonSteps.launchApp
|
||||
import org.isoron.uhabits.activities.about.AboutActivity
|
||||
import org.junit.Test
|
||||
import java.lang.Thread.sleep
|
||||
|
||||
@LargeTest
|
||||
class SavedStateTest : BaseUserInterfaceTest() {
|
||||
|
||||
/**
|
||||
* Make sure that the main activity can be recreated by using
|
||||
* BundleSavedState after being destroyed. See bug:
|
||||
* https://github.com/iSoron/uhabits/issues/287
|
||||
*/
|
||||
@Test
|
||||
@Throws(Exception::class)
|
||||
fun testBundleSavedState() {
|
||||
launchApp()
|
||||
startActivity(AboutActivity::class.java)
|
||||
sleep(1000)
|
||||
device.pressBack()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,154 @@
|
||||
/*
|
||||
* Copyright (C) 2016-2020 Á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.sync
|
||||
|
||||
import androidx.test.filters.MediumTest
|
||||
import com.fasterxml.jackson.databind.ObjectMapper
|
||||
import io.ktor.client.HttpClient
|
||||
import io.ktor.client.engine.mock.MockEngine
|
||||
import io.ktor.client.engine.mock.MockRequestHandleScope
|
||||
import io.ktor.client.engine.mock.respond
|
||||
import io.ktor.client.engine.mock.respondError
|
||||
import io.ktor.client.engine.mock.respondOk
|
||||
import io.ktor.client.features.json.JsonFeature
|
||||
import io.ktor.client.request.HttpRequestData
|
||||
import io.ktor.client.request.HttpResponseData
|
||||
import io.ktor.http.HttpStatusCode
|
||||
import io.ktor.http.fullPath
|
||||
import io.ktor.http.headersOf
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import org.isoron.uhabits.BaseAndroidTest
|
||||
import org.isoron.uhabits.core.sync.AbstractSyncServer
|
||||
import org.isoron.uhabits.core.sync.GetDataVersionResponse
|
||||
import org.isoron.uhabits.core.sync.KeyNotFoundException
|
||||
import org.isoron.uhabits.core.sync.RegisterReponse
|
||||
import org.isoron.uhabits.core.sync.ServiceUnavailable
|
||||
import org.isoron.uhabits.core.sync.SyncData
|
||||
import org.junit.Test
|
||||
|
||||
@MediumTest
|
||||
class RemoteSyncServerTest : BaseAndroidTest() {
|
||||
|
||||
private val mapper = ObjectMapper()
|
||||
val data = SyncData(1, "Hello world")
|
||||
|
||||
@Test
|
||||
fun when_register_succeeds_should_return_key() = runBlocking {
|
||||
val server = server("/register") {
|
||||
respondWithJson(RegisterReponse("ABCDEF"))
|
||||
}
|
||||
assertEquals("ABCDEF", server.register())
|
||||
}
|
||||
|
||||
@Test(expected = ServiceUnavailable::class)
|
||||
fun when_register_fails_should_raise_correct_exception() = runBlocking {
|
||||
val server = server("/register") {
|
||||
respondError(HttpStatusCode.ServiceUnavailable)
|
||||
}
|
||||
server.register()
|
||||
return@runBlocking
|
||||
}
|
||||
|
||||
@Test
|
||||
fun when_get_data_version_succeeds_should_return_version() = runBlocking {
|
||||
server("/db/ABC/version") {
|
||||
respondWithJson(GetDataVersionResponse(5))
|
||||
}.apply {
|
||||
assertEquals(5, getDataVersion("ABC"))
|
||||
}
|
||||
return@runBlocking
|
||||
}
|
||||
|
||||
@Test(expected = ServiceUnavailable::class)
|
||||
fun when_get_data_version_with_server_error_should_raise_exception() = runBlocking {
|
||||
server("/db/ABC/version") {
|
||||
respondError(HttpStatusCode.InternalServerError)
|
||||
}.apply {
|
||||
getDataVersion("ABC")
|
||||
}
|
||||
return@runBlocking
|
||||
}
|
||||
|
||||
@Test(expected = KeyNotFoundException::class)
|
||||
fun when_get_data_version_with_invalid_key_should_raise_exception() = runBlocking {
|
||||
server("/db/ABC/version") {
|
||||
respondError(HttpStatusCode.NotFound)
|
||||
}.apply {
|
||||
getDataVersion("ABC")
|
||||
}
|
||||
return@runBlocking
|
||||
}
|
||||
|
||||
@Test
|
||||
fun when_get_data_succeeds_should_return_data() = runBlocking {
|
||||
server("/db/ABC") {
|
||||
respondWithJson(data)
|
||||
}.apply {
|
||||
assertEquals(data, getData("ABC"))
|
||||
}
|
||||
return@runBlocking
|
||||
}
|
||||
|
||||
@Test(expected = KeyNotFoundException::class)
|
||||
fun when_get_data_with_invalid_key_should_raise_exception() = runBlocking {
|
||||
server("/db/ABC") {
|
||||
respondError(HttpStatusCode.NotFound)
|
||||
}.apply {
|
||||
getData("ABC")
|
||||
}
|
||||
return@runBlocking
|
||||
}
|
||||
|
||||
@Test
|
||||
fun when_put_succeeds_should_not_raise_exceptions() = runBlocking {
|
||||
server("/db/ABC") {
|
||||
respondOk()
|
||||
}.apply {
|
||||
put("ABC", data)
|
||||
}
|
||||
return@runBlocking
|
||||
}
|
||||
|
||||
private fun server(
|
||||
expectedPath: String,
|
||||
action: MockRequestHandleScope.(HttpRequestData) -> HttpResponseData
|
||||
): AbstractSyncServer {
|
||||
return RemoteSyncServer(
|
||||
httpClient = HttpClient(MockEngine) {
|
||||
install(JsonFeature)
|
||||
engine {
|
||||
addHandler { request ->
|
||||
when (request.url.fullPath) {
|
||||
expectedPath -> action(request)
|
||||
else -> error("unexpected call: ${request.url.fullPath}")
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
preferences = prefs
|
||||
)
|
||||
}
|
||||
|
||||
private fun MockRequestHandleScope.respondWithJson(content: Any) =
|
||||
respond(
|
||||
mapper.writeValueAsBytes(content),
|
||||
headers = headersOf("Content-Type" to listOf("application/json"))
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
/*
|
||||
* 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.widgets;
|
||||
|
||||
import android.widget.*;
|
||||
|
||||
import androidx.test.ext.junit.runners.*;
|
||||
import androidx.test.filters.*;
|
||||
|
||||
import org.isoron.uhabits.*;
|
||||
import org.isoron.uhabits.core.models.*;
|
||||
import org.isoron.uhabits.core.utils.*;
|
||||
import org.junit.*;
|
||||
import org.junit.runner.*;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.*;
|
||||
import static org.hamcrest.MatcherAssert.*;
|
||||
import static org.isoron.uhabits.core.models.Entry.*;
|
||||
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
@MediumTest
|
||||
public class CheckmarkWidgetTest extends BaseViewTest
|
||||
{
|
||||
private static final String PATH = "widgets/CheckmarkWidget/";
|
||||
|
||||
private Habit habit;
|
||||
|
||||
private EntryList entries;
|
||||
|
||||
private FrameLayout view;
|
||||
|
||||
private Timestamp today = DateUtils.getTodayWithOffset();
|
||||
|
||||
@Override
|
||||
public void setUp()
|
||||
{
|
||||
super.setUp();
|
||||
setTheme(R.style.WidgetTheme);
|
||||
prefs.setWidgetOpacity(255);
|
||||
prefs.setSkipEnabled(true);
|
||||
|
||||
habit = fixtures.createVeryLongHabit();
|
||||
entries = habit.getComputedEntries();
|
||||
CheckmarkWidget widget = new CheckmarkWidget(targetContext, 0, habit);
|
||||
view = convertToView(widget, 150, 200);
|
||||
|
||||
assertThat(entries.get(today).getValue(), equalTo(YES_MANUAL));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testClick() throws Exception
|
||||
{
|
||||
Button button = (Button) view.findViewById(R.id.button);
|
||||
assertThat(button, is(not(nullValue())));
|
||||
|
||||
// A better test would be to capture the intent, but it doesn't seem
|
||||
// possible to capture intents sent to BroadcastReceivers.
|
||||
button.performClick();
|
||||
sleep(1000);
|
||||
assertThat(entries.get(today).getValue(), equalTo(SKIP));
|
||||
|
||||
button.performClick();
|
||||
sleep(1000);
|
||||
assertThat(entries.get(today).getValue(), equalTo(NO));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIsInstalled()
|
||||
{
|
||||
assertWidgetProviderIsInstalled(CheckmarkWidgetProvider.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRender() throws Exception
|
||||
{
|
||||
assertRenders(view, PATH + "render.png");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
* 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.widgets;
|
||||
|
||||
import android.widget.*;
|
||||
|
||||
import androidx.test.ext.junit.runners.*;
|
||||
import androidx.test.filters.*;
|
||||
|
||||
import org.isoron.uhabits.*;
|
||||
import org.isoron.uhabits.core.models.*;
|
||||
import org.junit.*;
|
||||
import org.junit.runner.*;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
@MediumTest
|
||||
public class FrequencyWidgetTest extends BaseViewTest
|
||||
{
|
||||
private static final String PATH = "widgets/FrequencyWidget/";
|
||||
|
||||
private Habit habit;
|
||||
|
||||
private FrameLayout view;
|
||||
|
||||
@Override
|
||||
public void setUp()
|
||||
{
|
||||
super.setUp();
|
||||
setTheme(R.style.WidgetTheme);
|
||||
prefs.setWidgetOpacity(255);
|
||||
|
||||
habit = fixtures.createVeryLongHabit();
|
||||
FrequencyWidget widget = new FrequencyWidget(targetContext, 0, habit, Calendar.SUNDAY);
|
||||
view = convertToView(widget, 400, 400);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIsInstalled()
|
||||
{
|
||||
assertWidgetProviderIsInstalled(FrequencyWidgetProvider.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRender() throws Exception
|
||||
{
|
||||
assertRenders(view, PATH + "render.png");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
* 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.widgets;
|
||||
|
||||
import android.widget.*;
|
||||
|
||||
import androidx.test.ext.junit.runners.*;
|
||||
import androidx.test.filters.*;
|
||||
|
||||
import org.isoron.uhabits.*;
|
||||
import org.isoron.uhabits.core.models.*;
|
||||
import org.junit.*;
|
||||
import org.junit.runner.*;
|
||||
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
@MediumTest
|
||||
public class HistoryWidgetTest extends BaseViewTest
|
||||
{
|
||||
private static final String PATH = "widgets/HistoryWidget/";
|
||||
|
||||
private Habit habit;
|
||||
|
||||
private FrameLayout view;
|
||||
|
||||
@Override
|
||||
public void setUp()
|
||||
{
|
||||
super.setUp();
|
||||
setTheme(R.style.WidgetTheme);
|
||||
prefs.setWidgetOpacity(255);
|
||||
|
||||
habit = fixtures.createVeryLongHabit();
|
||||
HistoryWidget widget = new HistoryWidget(targetContext, 0, habit);
|
||||
view = convertToView(widget, 400, 400);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIsInstalled()
|
||||
{
|
||||
assertWidgetProviderIsInstalled(HistoryWidgetProvider.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRender() throws Exception
|
||||
{
|
||||
assertRenders(view, PATH + "render.png");
|
||||
}
|
||||
}
|
||||