Merge branch 'modules' into dev

pull/87/merge
Alinson S. Xavier 8 years ago
commit 5eb63df633

@ -1,147 +0,0 @@
apply plugin: 'com.android.application'
apply plugin: 'com.neenbedankt.android-apt'
apply plugin: 'me.tatarka.retrolambda'
apply plugin: 'jacoco'
android {
compileSdkVersion 25
buildToolsVersion "25.0.2"
defaultConfig {
applicationId "org.isoron.uhabits"
minSdkVersion 19
targetSdkVersion 25
buildConfigField "Integer", "databaseVersion", "19"
buildConfigField "String", "databaseFilename", "\"uhabits.db\""
buildConfigField "int", "roboSdk", (System.getenv("ROBO_SDK")?: "25")
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
testInstrumentationRunnerArgument "size", "medium"
}
buildTypes {
release {
minifyEnabled true
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt'
}
debug {
testCoverageEnabled = true
}
}
lintOptions {
checkReleaseBuilds false
}
compileOptions {
targetCompatibility 1.8
sourceCompatibility 1.8
}
testOptions {
unitTests.all {
testLogging {
events "passed", "skipped", "failed", "standardOut", "standardError"
outputs.upToDateWhen { false }
showStandardStreams = true
}
jacoco {
includeNoLocationClasses = true
}
}
}
}
dependencies {
androidTestApt 'com.google.dagger:dagger-compiler:2.11-rc2'
androidTestCompile 'com.android.support:support-annotations:25.3.1'
androidTestCompile 'com.android.support.test:rules:0.5'
androidTestCompile 'com.android.support.test:runner:0.5'
androidTestCompile 'com.google.auto.factory:auto-factory:1.0-beta3'
androidTestCompile "com.google.dexmaker:dexmaker:1.2"
androidTestCompile 'com.google.dexmaker:dexmaker-mockito:1.2'
androidTestCompile 'org.mockito:mockito-core:1.10.19'
androidTestCompile 'com.google.guava:guava:20.0'
apt 'com.google.dagger:dagger-compiler:2.11-rc2'
apt 'com.jakewharton:butterknife-compiler:8.6.1-SNAPSHOT'
compile 'com.android.support:appcompat-v7:25.3.1'
compile 'com.android.support:design:25.3.1'
compile 'com.android.support:preference-v14:25.3.1'
compile 'com.android.support:support-v4:25.3.1'
compile 'com.getpebble:pebblekit:3.0.0'
compile 'com.github.paolorotolo:appintro:3.4.0'
compile 'com.google.auto.factory:auto-factory:1.0-beta3'
compile 'com.google.dagger:dagger:2.11-rc2'
compile 'com.jakewharton:butterknife:8.6.1-SNAPSHOT'
compile 'com.michaelpardo:activeandroid:3.1.0-SNAPSHOT'
compile 'com.opencsv:opencsv:3.9'
compile 'org.apmem.tools:layouts:1.10'
compile 'org.jetbrains:annotations-java5:15.0'
compile 'com.google.code.gson:gson:2.7'
compile 'com.google.code.findbugs:jsr305:3.0.2'
compile 'com.google.guava:guava:20.0'
provided 'javax.annotation:jsr250-api:1.0'
compile ('io.socket:socket.io-client:+') {
exclude group: 'org.json', module: 'json'
}
testApt 'com.google.dagger:dagger-compiler:2.11-rc2'
testApt 'com.google.guava:guava:20.0'
testCompile 'junit:junit:5.0-SNAPSHOT'
testCompile 'org.hamcrest:hamcrest-library:1.4-atlassian-1'
testCompile 'org.mockito:mockito-core:2.8.9'
testCompile 'org.json:json:20160810'
testCompile 'org.robolectric:robolectric:3.4-rc2'
}
retrolambda {
defaultMethods true
}
jacoco {
toolVersion = "0.7.6.201602180812"
}
task coverageReport(type: JacocoReport, dependsOn: ['testDebugUnitTest']) {
jacocoClasspath = configurations['androidJacocoAnt']
reports {
html.enabled = true
xml.enabled = true
}
def excludes = [
'**/R.class',
'**/R$*.class',
'**/BuildConfig.*',
'**/Manifest*',
'**/*Test*.*',
'**/*$Lambda$*',
'**/*$ViewBinder*',
'**/*MembersInjector*',
'**/*_Provide*',
'**/*Module_*',
'**/com/android/**/*',
'android/**/*',
'**/*Dagger*',
'**/*_Factory*'
]
def srcDir = "${project.projectDir}/src/main/java"
def classDir = "${buildDir}/intermediates/classes/debug"
def jvmExecData = "${buildDir}/jacoco/testDebugUnitTest.exec"
def connectedExecData = "${buildDir}/outputs/code-coverage/connected/coverage.ec"
sourceDirectories = files(srcDir)
classDirectories = files(fileTree(dir: classDir, excludes: excludes))
executionData = files(jvmExecData, connectedExecData)
}

@ -1,59 +0,0 @@
/*
* 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.utils;
import android.appwidget.*;
import android.content.*;
import android.os.*;
import android.support.annotation.*;
import android.widget.*;
import org.isoron.uhabits.widgets.*;
import static android.appwidget.AppWidgetManager.*;
import static org.isoron.uhabits.utils.InterfaceUtils.*;
public abstract class WidgetUtils
{
@NonNull
public static WidgetDimensions getDimensionsFromOptions(
@NonNull Context ctx, @NonNull Bundle options)
{
int maxWidth =
(int) dpToPixels(ctx, options.getInt(OPTION_APPWIDGET_MAX_WIDTH));
int maxHeight =
(int) dpToPixels(ctx, options.getInt(OPTION_APPWIDGET_MAX_HEIGHT));
int minWidth =
(int) dpToPixels(ctx, options.getInt(OPTION_APPWIDGET_MIN_WIDTH));
int minHeight =
(int) dpToPixels(ctx, options.getInt(OPTION_APPWIDGET_MIN_HEIGHT));
return new WidgetDimensions(minWidth, maxHeight, maxWidth, minHeight);
}
public static void updateAppWidget(@NonNull AppWidgetManager manager,
@NonNull BaseWidget widget)
{
RemoteViews landscape = widget.getLandscapeRemoteViews();
RemoteViews portrait = widget.getPortraitRemoteViews();
RemoteViews views = new RemoteViews(landscape, portrait);
manager.updateAppWidget(widget.getId(), views);
}
}

@ -1,199 +0,0 @@
/*
* 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.activities;
import android.content.*;
import android.os.*;
import android.support.v4.app.*;
import android.support.v7.app.*;
import android.support.v7.widget.Toolbar;
import android.view.*;
import android.widget.*;
import org.isoron.uhabits.*;
import org.isoron.uhabits.activities.common.dialogs.*;
import org.junit.*;
import org.junit.runner.*;
import org.robolectric.*;
import org.robolectric.annotation.*;
import org.robolectric.shadows.*;
import static org.hamcrest.core.IsEqual.*;
import static org.junit.Assert.*;
import static org.mockito.Mockito.*;
import static org.robolectric.Robolectric.*;
import static org.robolectric.Shadows.*;
@RunWith(RobolectricTestRunner.class)
@Config(sdk = BuildConfig.roboSdk, constants = BuildConfig.class)
public class BaseActivityTest
{
private static boolean hasCrashed = false;
@Test
public void activityResultTest()
{
ScreenActivity activity = spy(setupActivity(ScreenActivity.class));
activity.onActivityResult(0, 0, null);
verify(activity.screen).onResult(0, 0, null);
}
@Test
public void componentTest()
{
EmptyActivity activity = setupActivity(EmptyActivity.class);
ActivityComponent component = activity.getComponent();
assertThat(component.getActivity(), equalTo(activity));
}
@Test
public void dialogFragmentTest()
{
EmptyActivity activity = setupActivity(EmptyActivity.class);
FragmentManager manager = activity.getSupportFragmentManager();
ColorPickerDialog d = new ColorPickerDialogFactory(activity).create(0);
activity.showDialog(d, "picker");
assertTrue(d.getDialog().isShowing());
assertThat(d, equalTo(manager.findFragmentByTag("picker")));
}
@Test
public void dialogTest()
{
EmptyActivity activity = setupActivity(EmptyActivity.class);
AlertDialog dialog =
new AlertDialog.Builder(activity).setTitle("Hello world").create();
activity.showDialog(dialog);
assertTrue(dialog.isShowing());
}
@Test
public void restartTest() throws Exception
{
EmptyActivity activity = setupActivity(EmptyActivity.class);
activity.restartWithFade(EmptyActivity.class);
ShadowLooper.runUiThreadTasksIncludingDelayedTasks();
Intent nextStartedActivity = shadowOf(activity).getNextStartedActivity();
assertNotNull(nextStartedActivity);
assertTrue(activity.isFinishing());
assertThat(shadowOf(nextStartedActivity).getIntentClass(),
equalTo(EmptyActivity.class));
}
@Test
public void exceptionHandlerTest() throws InterruptedException
{
assertFalse(hasCrashed);
Thread crashThread = new Thread()
{
@Override
public void run()
{
Looper.prepare();
CrashActivity activity = setupActivity(CrashActivity.class);
activity.crash();
}
};
crashThread.start();
crashThread.join();
assertTrue(hasCrashed);
}
@Test
public void menuTest()
{
MenuActivity activity = setupActivity(MenuActivity.class);
verify(activity.baseMenu).onCreate(eq(activity.getMenuInflater()),
any());
Menu menu = activity.toolbar.getMenu();
MenuItem item = menu.getItem(0);
activity.onMenuItemSelected(0, item);
verify(activity.baseMenu).onItemSelected(item);
}
static class CrashActivity extends BaseActivity
{
public void crash()
{
throw new RuntimeException("crash!");
}
@Override
protected Thread.UncaughtExceptionHandler getExceptionHandler()
{
return (t, e) -> hasCrashed = true;
}
}
static class EmptyActivity extends BaseActivity
{
}
static class MenuActivity extends BaseActivity
{
public BaseMenu baseMenu;
public Toolbar toolbar;
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
toolbar = new Toolbar(this);
LinearLayout layout = new LinearLayout(this);
layout.addView(toolbar);
setContentView(layout);
setSupportActionBar(toolbar);
baseMenu = spy(new BaseMenu(this)
{
@Override
protected int getMenuResourceId()
{
return R.menu.list_habits;
}
});
setBaseMenu(baseMenu);
}
}
static class ScreenActivity extends BaseActivity
{
private BaseScreen screen;
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
screen = spy(new BaseScreen(this));
setScreen(screen);
}
}
}

@ -1,140 +0,0 @@
/*
* 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.activities;
import android.content.*;
import android.support.annotation.*;
import android.support.v7.view.ActionMode;
import android.support.v7.widget.*;
import android.view.*;
import org.isoron.uhabits.*;
import org.junit.*;
import org.junit.runner.*;
import org.robolectric.*;
import org.robolectric.annotation.*;
import java.util.*;
import static android.view.View.*;
import static junit.framework.Assert.assertNotNull;
import static org.hamcrest.core.IsEqual.*;
import static org.junit.Assert.*;
import static org.mockito.Matchers.any;
import static org.mockito.Mockito.*;
import static org.robolectric.Robolectric.*;
@RunWith(RobolectricTestRunner.class)
@Config(sdk = BuildConfig.roboSdk, constants = BuildConfig.class)
public class BaseScreenTest
{
@Test
public void selectionMenuTest()
{
BaseSelectionMenu selectionMenu = spy(new BaseSelectionMenu()
{
@Override
protected int getResourceId()
{
return R.menu.list_habits_selection;
}
});
ActionModeActivity activity = setupActivity(ActionModeActivity.class);
BaseScreen screen = new BaseScreen(activity);
screen.setSelectionMenu(selectionMenu);
activity.setScreen(screen);
screen.startSelection();
assertNotNull(activity.callback);
verify(selectionMenu).onCreate(any(), any(), any());
verify(selectionMenu).onPrepare(any());
ActionMode mode = mock(ActionMode.class);
MenuItem item = mock(MenuItem.class);
activity.callback.onActionItemClicked(mode, item);
verify(selectionMenu).onItemClicked(item);
activity.callback.onDestroyActionMode(mode);
verify(selectionMenu).onFinish();
}
@Test
public void showMessageTest()
{
EmptyActivity activity = setupActivity(EmptyActivity.class);
ConcreteRootView rootView = new ConcreteRootView(activity);
View decor = activity.getWindow().getDecorView();
BaseScreen screen = new BaseScreen(activity);
screen.setRootView(rootView);
activity.setScreen(screen);
ArrayList<View> matches = new ArrayList<>();
screen.showMessage(R.string.checkmark);
decor.findViewsWithText(matches, "Checkmark", FIND_VIEWS_WITH_TEXT);
assertThat(matches.size(), equalTo(1));
assertTrue(matches.get(0).isShown());
screen.showMessage(R.string.frequency);
decor.findViewsWithText(matches, "Frequency", FIND_VIEWS_WITH_TEXT);
assertThat(matches.size(), equalTo(1));
assertTrue(matches.get(0).isShown());
}
static class ActionModeActivity extends BaseActivity
{
private ActionMode.Callback callback;
@Nullable
@Override
public ActionMode startSupportActionMode(
@NonNull ActionMode.Callback callback)
{
this.callback = callback;
return super.startSupportActionMode(this.callback);
}
}
static class ConcreteRootView extends BaseRootView
{
private final Toolbar toolbar;
public ConcreteRootView(@NonNull Context context)
{
super(context);
toolbar = new Toolbar(context);
addView(toolbar);
}
@NonNull
@Override
public Toolbar getToolbar()
{
return toolbar;
}
}
static class EmptyActivity extends BaseActivity
{
}
}

@ -1,129 +0,0 @@
/*
* 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;
import org.isoron.uhabits.*;
import org.isoron.uhabits.activities.*;
import org.isoron.uhabits.activities.habits.list.model.*;
import org.isoron.uhabits.commands.*;
import org.isoron.uhabits.models.*;
import org.isoron.uhabits.preferences.*;
import org.isoron.uhabits.tasks.*;
import org.isoron.uhabits.utils.*;
import org.isoron.uhabits.widgets.*;
import org.junit.*;
import static org.mockito.Mockito.*;
public class ListHabitsControllerTest extends BaseUnitTest
{
private ListHabitsController controller;
private ImportDataTaskFactory importTaskFactory;
private BaseSystem system;
private CommandRunner commandRunner;
private HabitCardListAdapter adapter;
private ListHabitsScreen screen;
private Preferences prefs;
private ReminderScheduler reminderScheduler;
private SingleThreadTaskRunner taskRunner;
private WidgetUpdater widgetUpdater;
private ExportCSVTaskFactory exportCSVFactory;
private ExportDBTaskFactory exportDBFactory;
@Override
public void setUp()
{
super.setUp();
habitList = mock(HabitList.class);
system = mock(BaseSystem.class);
commandRunner = mock(CommandRunner.class);
adapter = mock(HabitCardListAdapter.class);
screen = mock(ListHabitsScreen.class);
prefs = mock(Preferences.class);
reminderScheduler = mock(ReminderScheduler.class);
taskRunner = new SingleThreadTaskRunner();
widgetUpdater = mock(WidgetUpdater.class);
importTaskFactory = mock(ImportDataTaskFactory.class);
exportCSVFactory = mock(ExportCSVTaskFactory.class);
exportDBFactory = mock(ExportDBTaskFactory.class);
controller =
spy(new ListHabitsController(system, commandRunner, habitList,
adapter, screen, prefs, reminderScheduler, taskRunner,
widgetUpdater, importTaskFactory, exportCSVFactory, exportDBFactory));
}
@Test
public void testOnHabitClick()
{
Habit h = mock(Habit.class);
controller.onHabitClick(h);
verify(screen).showHabitScreen(h);
}
@Test
public void testOnHabitReorder()
{
Habit from = mock(Habit.class);
Habit to = mock(Habit.class);
controller.onHabitReorder(from, to);
verify(habitList).reorder(from, to);
}
@Test
public void onInvalidToggle()
{
controller.onInvalidToggle();
verify(screen).showMessage(R.string.long_press_to_toggle);
}
@Test
public void onStartup_notFirstLaunch()
{
when(prefs.isFirstRun()).thenReturn(false);
controller.onStartup();
verify(prefs).incrementLaunchCount();
}
@Test
public void onStartup_firstLaunch()
{
long today = DateUtils.getStartOfToday();
when(prefs.isFirstRun()).thenReturn(true);
controller.onStartup();
verify(prefs).setFirstRun(false);
verify(prefs).updateLastHint(-1, today);
verify(screen).showIntroScreen();
}
}

@ -1,81 +0,0 @@
/*
* 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;
import android.view.*;
import org.isoron.uhabits.*;
import org.isoron.uhabits.models.*;
import org.isoron.uhabits.tasks.*;
import org.junit.*;
import static org.mockito.Matchers.any;
import static org.mockito.Mockito.*;
public class ShowHabitsMenuTest extends BaseUnitTest
{
private ShowHabitActivity activity;
private ShowHabitScreen screen;
private ShowHabitsMenu menu;
private Habit habit;
private ExportCSVTaskFactory exportCSVFactory;
private TaskRunner taskRunner;
private ExportCSVTask task;
@Override
public void setUp()
{
super.setUp();
activity = mock(ShowHabitActivity.class);
screen = mock(ShowHabitScreen.class);
habit = mock(Habit.class);
exportCSVFactory = mock(ExportCSVTaskFactory.class);
taskRunner = mock(TaskRunner.class);
menu = new ShowHabitsMenu(activity, screen, habit, exportCSVFactory,
taskRunner);
}
@Test
public void testOnDownloadHabit()
{
onItemSelected(R.id.export);
verify(taskRunner).execute(any());
}
@Test
public void testOnEditHabit()
{
onItemSelected(R.id.action_edit_habit);
verify(screen).showEditHabitDialog();
}
protected void onItemSelected(int actionId)
{
MenuItem item = mock(MenuItem.class);
when(item.getItemId()).thenReturn(actionId);
menu.onItemSelected(item);
}
}

@ -1,21 +1,22 @@
// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
repositories {
jcenter()
maven { url 'https://maven.google.com' }
}
dependencies {
classpath 'com.android.tools.build:gradle:2.3.2'
classpath 'com.android.tools.build:gradle:3.0.0-alpha2'
classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8'
classpath 'com.getkeepsafe.dexcount:dexcount-gradle-plugin:0.6.4'
classpath 'me.tatarka:gradle-retrolambda:3.2.5'
classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8'
classpath 'org.jacoco:org.jacoco.core:+'
}
}
allprojects {
repositories {
jcenter()
maven { url 'https://maven.google.com' }
maven { url "https://oss.sonatype.org/content/repositories/snapshots/" }
}
}

@ -19,7 +19,7 @@ ADB="${ANDROID_HOME}/platform-tools/adb"
EMULATOR="${ANDROID_HOME}/tools/emulator"
GRADLE="./gradlew --stacktrace"
PACKAGE_NAME=org.isoron.uhabits
OUTPUTS_DIR=app/build/outputs
OUTPUTS_DIR=uhabits-android/build/outputs
KEYFILE="TestKeystore.jks"
KEY_ALIAS="default"
@ -120,6 +120,12 @@ uninstall_apk() {
$ADB uninstall ${PACKAGE_NAME}
}
install_test_butler() {
log_info "Installing Test Butler"
$ADB install tools/test-butler-app-1.3.1.apk
$ADB uninstall com.linkedin.android.testbutler
}
install_apk() {
if [ ! -z $UNINSTALL_FIRST ]; then
uninstall_apk
@ -128,14 +134,14 @@ install_apk() {
log_info "Installing APK"
if [ ! -z $RELEASE ]; then
$ADB install -r ${OUTPUTS_DIR}/apk/app-release.apk || fail
$ADB install -r ${OUTPUTS_DIR}/apk/release/uhabits-android-release.apk || fail
else
$ADB install -r ${OUTPUTS_DIR}/apk/app-debug.apk || fail
$ADB install -r ${OUTPUTS_DIR}/apk/debug/uhabits-android-debug.apk || fail
fi
}
install_test_apk() {
$ADB install -r ${OUTPUTS_DIR}/apk/app-debug-androidTest.apk || fail
$ADB install -r ${OUTPUTS_DIR}/apk/androidTest/debug/uhabits-android-debug-androidTest.apk || fail
}
run_instrumented_tests() {
@ -143,7 +149,7 @@ run_instrumented_tests() {
$ADB shell am instrument \
-r -e coverage true -e size medium \
-w ${PACKAGE_NAME}.test/android.support.test.runner.AndroidJUnitRunner \
> ${OUTPUTS_DIR}/instrument.txt
| tee ${OUTPUTS_DIR}/instrument.txt
mkdir -p ${OUTPUTS_DIR}/code-coverage/connected/
$ADB pull /data/user/0/${PACKAGE_NAME}/files/coverage.ec \
@ -157,8 +163,12 @@ parse_instrumentation_results() {
}
generate_coverage_badge() {
log_info "Generating code coverage badge"
python tools/coverage-badge/badge.py -i app/build/reports/jacoco/coverageReport/coverageReport.xml -o ${OUTPUTS_DIR}/coverage-badge
log_info "Generating code coverage report and badge"
$GRADLE coverageReport || fail
ANDROID_REPORT=uhabits-android/build/reports/jacoco/coverageReport/coverageReport.xml
CORE_REPORT=uhabits-core/build/reports/jacoco/test/jacocoTestReport.xml
python tools/coverage-badge/badge.py -i $ANDROID_REPORT:$CORE_REPORT -o ${OUTPUTS_DIR}/coverage-badge
}
fetch_artifacts() {
@ -180,7 +190,7 @@ fetch_logcat() {
run_jvm_tests() {
log_info "Running JVM tests"
$GRADLE --no-daemon coverageReport || fail
$GRADLE testDebugUnitTest :uhabits-core:check || fail
}
uninstall_test_apk() {
@ -193,6 +203,7 @@ run_local_tests() {
run_adb_as_root
build_apk
build_instrumentation_apk
install_test_butler
install_apk
install_test_apk
run_instrumented_tests

@ -1,6 +1,6 @@
#Fri Mar 17 21:42:38 EDT 2017
#Wed May 24 19:36:48 EDT 2017
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-3.5-all.zip
distributionUrl=https\://services.gradle.org/distributions-snapshots/gradle-4.0-20170417000025+0000-all.zip

@ -1 +1 @@
include ':app'
include ':uhabits-android', ':uhabits-core'

@ -44,10 +44,13 @@ class Devnull(object):
def get_total(report):
doc = BeautifulSoup(file(report), 'xml')
tag = doc.select("report > counter[type^INST]")[0]
missed = float(tag['missed'])
covered = float(tag['covered'])
missed = 0
covered = 0
for r in report.split(":"):
doc = BeautifulSoup(file(r), 'xml')
tag = doc.select("report > counter[type^INST]")[0]
missed = missed + float(tag['missed'])
covered = covered + float(tag['covered'])
return str(int(round(100 * covered / (missed + covered))))
def get_color(total):

Binary file not shown.

@ -0,0 +1,145 @@
apply plugin: 'idea'
apply plugin: 'com.android.application'
apply plugin: 'jacoco'
android {
compileSdkVersion 25
buildToolsVersion "25.0.2"
defaultConfig {
applicationId "org.isoron.uhabits"
minSdkVersion 19
targetSdkVersion 25
buildConfigField "Integer", "databaseVersion", "19"
buildConfigField "String", "databaseFilename", "\"uhabits.db\""
buildConfigField "int", "roboSdk", (System.getenv("ROBO_SDK") ?: "25")
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled true
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt'
}
debug {
testCoverageEnabled true
}
}
lintOptions {
checkReleaseBuilds false
}
compileOptions {
targetCompatibility JavaVersion.VERSION_1_8
sourceCompatibility JavaVersion.VERSION_1_8
}
testOptions {
unitTests.all {
testLogging {
events "passed", "skipped", "failed", "standardOut", "standardError"
outputs.upToDateWhen { false }
showStandardStreams = true
}
jacoco {
includeNoLocationClasses = true
}
}
}
}
dependencies {
implementation project(":uhabits-core")
implementation 'com.android.support:appcompat-v7:25.3.1'
implementation 'com.android.support:design:25.3.1'
implementation 'com.android.support:preference-v14:25.3.1'
implementation 'com.android.support:support-v4:25.3.1'
implementation 'com.getpebble:pebblekit:3.0.0'
implementation 'com.github.paolorotolo:appintro:3.4.0'
implementation 'com.google.dagger:dagger:2.9'
implementation 'com.jakewharton:butterknife:8.6.1-SNAPSHOT'
implementation 'com.michaelpardo:activeandroid:3.1.0-SNAPSHOT'
implementation 'org.apmem.tools:layouts:1.10'
implementation 'org.jetbrains:annotations-java5:15.0'
implementation 'com.google.code.gson:gson:2.7'
implementation 'com.google.code.findbugs:jsr305:3.0.2'
compileOnly 'javax.annotation:jsr250-api:1.0'
compileOnly 'com.google.auto.factory:auto-factory:1.0-beta3'
annotationProcessor 'com.google.dagger:dagger-compiler:2.9'
annotationProcessor 'com.jakewharton:butterknife-compiler:8.6.1-SNAPSHOT'
annotationProcessor 'com.google.auto.factory:auto-factory:1.0-beta3'
androidTestImplementation project(":uhabits-core")
androidTestImplementation 'com.android.support:support-annotations:25.3.1'
androidTestImplementation 'com.android.support.test:rules:0.5'
androidTestImplementation 'com.android.support.test:runner:0.5'
androidTestImplementation 'com.google.guava:guava:20.0'
androidTestCompileOnly 'com.google.auto.factory:auto-factory:1.0-beta3'
androidTestAnnotationProcessor 'com.google.dagger:dagger-compiler:2.9'
androidTestAnnotationProcessor 'com.google.auto.factory:auto-factory:1.0-beta3'
androidTestAnnotationProcessor 'com.jakewharton:butterknife-compiler:8.6.1-SNAPSHOT'
testAnnotationProcessor 'com.google.dagger:dagger-compiler:2.9'
testAnnotationProcessor 'com.google.auto.factory:auto-factory:1.0-beta3'
testAnnotationProcessor 'com.jakewharton:butterknife-compiler:8.6.1-SNAPSHOT'
testCompile 'com.google.dagger:dagger:2.9'
testCompile "org.mockito:mockito-core:2.8.9"
testCompile "org.mockito:mockito-inline:2.8.9"
androidTestCompile 'com.google.dagger:dagger:2.9'
androidTestCompile "org.mockito:mockito-android:2.8.9"
androidTestCompile 'com.android.support.test.espresso:espresso-core:2.2.2'
androidTestCompile 'com.android.support.test.uiautomator:uiautomator-v18:2.1.1'
androidTestCompile 'com.android.support.test.espresso:espresso-core:2.2.2'
androidTestCompile 'com.android.support.test.espresso:espresso-contrib:2.2.2'
androidTestCompile 'com.linkedin.testbutler:test-butler-library:1.3.1'
implementation('com.opencsv:opencsv:3.9') {
exclude group: 'commons-logging', module: 'commons-logging'
}
implementation('io.socket:socket.io-client:+') {
exclude group: 'org.json', module: 'json'
}
}
repositories {
mavenCentral()
}
task coverageReport(type: JacocoReport) {
jacocoClasspath = configurations['androidJacocoAnt']
reports {
html.enabled = true
xml.enabled = true
}
def excludes = [
'**/R.class',
'**/R$*.class',
'**/BuildConfig.*',
'**/Manifest*',
'**/*Test*.*',
'**/*$Lambda$*',
'**/*$ViewBinder*',
'**/*MembersInjector*',
'**/*_Provide*',
'**/*Module_*',
'**/com/android/**/*',
'**/*Dagger*',
'**/*_Factory*'
]
def androidSrc = "${project.projectDir}/src/main/java"
def androidClasses = "${buildDir}/intermediates/classes/debug"
def jvmExecData = "${buildDir}/jacoco/testDebugUnitTest.exec"
def connectedExecData = "${buildDir}/outputs/code-coverage/connected/coverage.ec"
sourceDirectories = files(androidSrc)
classDirectories = files(fileTree(dir: androidClasses, excludes: excludes))
executionData = files(jvmExecData, connectedExecData)
}

@ -0,0 +1,27 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ 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/>.
-->
<manifest
package="org.isoron.uhabits"
xmlns:android="http://schemas.android.com/apk/res/android">
<instrumentation>
<meta-data android:name="notPackage" android:value="net.bytebuddy"/>
</instrumentation>
</manifest>

Before

Width:  |  Height:  |  Size: 48 KiB

After

Width:  |  Height:  |  Size: 48 KiB

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save