Added tests for popup notification manager

This commit is contained in:
Keith Holliday 2016-12-11 14:12:36 -06:00
parent 7badf0190f
commit 8d1ba18b3f
3 changed files with 400 additions and 288 deletions

View file

@ -1,279 +1,291 @@
apply plugin: 'com.android.application'
apply plugin: 'com.android.databinding'
apply plugin: 'io.fabric'
apply plugin: 'com.neenbedankt.android-apt'
buildscript {
repositories {
mavenLocal()
mavenCentral()
maven { url 'https://maven.fabric.io/public' }
}
dependencies {
classpath 'io.fabric.tools:gradle:1.21.5'
classpath 'me.tatarka:gradle-retrolambda:3.3.1'
classpath 'com.getkeepsafe.dexcount:dexcount-gradle-plugin:0.6.1'
classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8'
}
}
repositories {
mavenLocal()
mavenCentral()
maven { url "https://oss.sonatype.org/content/repositories/snapshots" }
maven { url 'https://maven.fabric.io/public' }
// Material View Pager
maven { url "http://dl.bintray.com/florent37/maven" }
// Markdown
maven { url "https://s3.amazonaws.com/repo.commonsware.com" }
maven { url "https://jitpack.io" }
}
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
//Networking
compile 'com.squareup.okhttp3:okhttp:3.4.1'
compile 'com.squareup.okhttp3:logging-interceptor:3.4.1'
//REST API handling
compile('com.squareup.retrofit2:retrofit:2.1.0') {
exclude module: 'okhttp'
}
compile 'com.squareup.retrofit2:converter-gson:2.1.0'
compile 'com.squareup.retrofit2:adapter-rxjava:2.1.0'
//Crash Logging
releaseCompile('com.crashlytics.sdk.android:crashlytics:2.6.0@aar') {
transitive = true;
}
// View Elements Binding :)
compile 'com.jakewharton:butterknife:8.4.0'
apt 'com.jakewharton:butterknife-compiler:8.4.0'
//Dependency Injection
compile 'com.google.dagger:dagger:2.7'
apt 'com.google.dagger:dagger-compiler:2.7'
provided 'org.glassfish:javax.annotation:10.0-b28'
//App Compatibility and Material Design
compile('com.mikepenz:materialdrawer:5.3.6@aar') {
transitive = true
}
compile 'com.android.support:appcompat-v7:25.0.1'
compile 'com.android.support:design:25.0.1'
compile 'com.android.support:recyclerview-v7:25.0.1'
compile 'com.android.support:preference-v14:25.0.1'
compile 'com.android.support:multidex:1.0.1'
//QR Code
compile 'com.github.kenglxn.QRGen:android:2.2.0'
// Emojis
compile 'com.github.viirus:emoji-lib:0.0.3.2'
// Markdown
compile 'com.commonsware.cwac:anddown:0.2.4'
// About View for all dependent Libraries, we are using
compile('com.mikepenz:aboutlibraries:5.7.1@aar') {
transitive = true
}
// a better fab alternative
compile 'com.github.clans:fab:1.6.4'
// ORM
apt 'com.raizlabs.android:DBFlow-Compiler:2.2.1'
compile "com.raizlabs.android:DBFlow-Core:2.2.1"
compile "com.raizlabs.android:DBFlow:2.2.1"
//Eventbus
compile 'org.greenrobot:eventbus:3.0.0'
// IAP Handling / Verification
compile 'org.solovyev.android:checkout:0.7.5@aar'
//Facebook
compile('com.facebook.android:facebook-android-sdk:4.17.0') {
transitive = true
}
compile 'fr.avianey.com.viewpagerindicator:library:2.4.1@aar'
//RxJava
compile 'io.reactivex:rxandroid:1.2.1'
compile 'io.reactivex:rxjava:1.2.0'
//Analytics
compile 'com.amplitude:android-sdk:2.9.2'
// Fresco Image Management Library
compile('com.facebook.fresco:fresco:0.14.0') {
exclude module: 'bolts-android'
}
compile('com.facebook.fresco:animated-gif:0.14.0') {
exclude module: 'bolts-android'
}
//Tests
testCompile "junit:junit:4.10"
testCompile "org.assertj:assertj-core:1.7.0"
testCompile 'com.squareup.leakcanary:leakcanary-android-no-op:1.5'
testCompile "org.robolectric:robolectric:3.1"
testCompile 'org.robolectric:shadows-multidex:3.1'
testCompile "org.robolectric:shadows-support-v4:3.1"
testCompile "org.mockito:mockito-core:1.10.19"
//Leak Detection
debugCompile 'com.squareup.leakcanary:leakcanary-android:1.5'
releaseCompile 'com.squareup.leakcanary:leakcanary-android-no-op:1.5'
//Push Notifications
compile 'com.google.firebase:firebase-core:9.4.0'
compile 'com.google.firebase:firebase-messaging:9.4.0'
compile 'com.google.android.gms:play-services-auth:9.4.0'
compile(project(':seeds-sdk')) {
exclude group: 'com.google.android.gms'
exclude group: 'com.android.support', module: 'multidex'
}
}
android {
compileSdkVersion 25
buildToolsVersion "24.0.3"
defaultConfig {
applicationId "com.habitrpg.android.habitica"
}
lintOptions {
abortOnError false
}
signingConfigs {
release
}
buildTypes {
debug {
applicationIdSuffix ".debug"
debuggable true
multiDexEnabled true
// Disable fabric build ID generation for debug builds
ext.enableCrashlytics = false
resValue "string", "content_provider", "com.habitrpg.android.habitica.debug.fileprovider"
resValue "string", "app_name", "Habitica Debug"
}
release {
signingConfig signingConfigs.release
debuggable false
multiDexEnabled true
resValue "string", "content_provider", "com.habitrpg.android.habitica.fileprovider"
resValue "string", "app_name", "Habitica"
}
}
sourceSets {
main {
manifest.srcFile 'AndroidManifest.xml'
java.srcDirs = ['src/main/java']
resources.srcDirs = ['src/main/java']
aidl.srcDirs = ['src/main/java']
renderscript.srcDirs = ['src/main/java']
res.srcDirs = ['res']
assets.srcDirs = ['assets']
}
robolectric {
manifest.srcFile 'AndroidManifestTesting.xml'
java.srcDir file('src/test/java/')
res.srcDirs = ['res']
}
instrumentTest.setRoot('tests')
release { java.srcDirs = ['src/release/java'] }
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
dexOptions {
preDexLibraries false
javaMaxHeapSize "4g" // Use gig increments depending on needs
}
lintOptions {
disable 'UnusedResources'
}
}
def Properties props = new Properties()
def propFile = new File('signingrelease.properties')
if (propFile.canRead()) {
props.load(new FileInputStream(propFile))
if (props != null && props.containsKey('STORE_FILE') && props.containsKey('STORE_PASSWORD') &&
props.containsKey('KEY_ALIAS') && props.containsKey('KEY_PASSWORD')) {
android.signingConfigs.release.storeFile = file(props['STORE_FILE'])
android.signingConfigs.release.storePassword = props['STORE_PASSWORD']
android.signingConfigs.release.keyAlias = props['KEY_ALIAS']
android.signingConfigs.release.keyPassword = props['KEY_PASSWORD']
} else {
println 'signing.properties found but some entries are missing'
android.buildTypes.release.signingConfig = null
}
} else {
println 'signing.properties not found'
android.buildTypes.release.signingConfig = null
}
// Add Habitica Properties to buildConfigField
final File HRPG_PROPS_FILE = new File('habitica.properties')
if (HRPG_PROPS_FILE.canRead()) {
def Properties HRPG_PROPS = new Properties()
HRPG_PROPS.load(new FileInputStream(HRPG_PROPS_FILE))
if (HRPG_PROPS != null) {
android.buildTypes.all { buildType ->
HRPG_PROPS.any { property ->
buildType.buildConfigField "String", property.key, "\"${property.value}\""
}
}
} else {
throw new InvalidUserDataException('habitica.properties found but some entries are missing')
}
} else {
throw new MissingResourceException('habitica.properties not found')
}
// Add Habitica Resources to resources
final File HRPG_RES_FILE = new File('habitica.resources')
if (HRPG_RES_FILE.canRead()) {
def Properties HRPG_RES = new Properties()
HRPG_RES.load(new FileInputStream(HRPG_RES_FILE))
if (HRPG_RES != null) {
android.buildTypes.all { buildType ->
HRPG_RES.any { property ->
buildType.resValue "string", property.key, "\"${property.value}\""
}
}
} else {
throw new InvalidUserDataException('habitica.resources found but some entries are missing')
}
} else {
throw new MissingResourceException('habitica.resources not found')
}
tasks.whenTaskAdded { task ->
if (task.name.equals("lint")) {
task.enabled = false
}
}
apply plugin: 'com.getkeepsafe.dexcount'
apply plugin: 'com.android.application' //or apply plugin: 'java'
apply plugin: 'me.tatarka.retrolambda'
apply plugin: 'com.google.gms.google-services'
apply plugin: 'com.android.application'
apply plugin: 'com.android.databinding'
apply plugin: 'io.fabric'
apply plugin: 'com.neenbedankt.android-apt'
buildscript {
repositories {
mavenLocal()
mavenCentral()
maven { url 'https://maven.fabric.io/public' }
}
dependencies {
classpath 'io.fabric.tools:gradle:1.21.5'
classpath 'me.tatarka:gradle-retrolambda:3.2.5'
classpath 'com.getkeepsafe.dexcount:dexcount-gradle-plugin:0.6.1'
classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8'
classpath 'com.jakewharton.hugo:hugo-plugin:1.2.1'
}
}
repositories {
mavenLocal()
mavenCentral()
maven {
url "https://oss.sonatype.org/content/repositories/snapshots"
}
maven { url 'https://maven.fabric.io/public' }
// Material View Pager
maven {
url "http://dl.bintray.com/florent37/maven"
}
// Markdown
maven {
url "https://s3.amazonaws.com/repo.commonsware.com"
}
maven {
url "https://jitpack.io"
}
}
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
//Networking
compile 'com.squareup.okhttp3:okhttp-urlconnection:3.4.1'
compile 'com.squareup.okhttp3:okhttp:3.4.1'
compile 'com.squareup.okhttp3:logging-interceptor:3.4.1'
//REST API handling
compile ('com.squareup.retrofit2:retrofit:2.1.0') {
exclude module: 'okhttp'
}
compile 'com.squareup.retrofit2:converter-gson:2.1.0'
compile 'com.squareup.retrofit2:adapter-rxjava:2.1.0'
//Crash Logging
compile('com.crashlytics.sdk.android:crashlytics:2.6.0@aar') {
transitive = true;
}
// View Elements Binding :)
compile 'com.jakewharton:butterknife:8.2.1'
apt 'com.jakewharton:butterknife-compiler:8.2.1'
//Dependency Injection
compile 'com.google.dagger:dagger:2.5'
apt 'com.google.dagger:dagger-compiler:2.5'
provided 'org.glassfish:javax.annotation:10.0-b28'
//App Compatibility and Material Design
compile('com.mikepenz:materialdrawer:5.3.6@aar') {
transitive = true
}
compile 'com.android.support:appcompat-v7:24.2.1'
compile 'com.android.support:design:24.2.1'
compile 'com.android.support:gridlayout-v7:24.2.1'
compile 'com.android.support:recyclerview-v7:24.2.1'
compile 'com.android.support:preference-v14:24.2.1'
compile 'com.android.support:multidex:1.0.1'
// Image Loading/Caching
compile 'com.squareup.picasso:picasso:2.5.2'
//QR Code
compile 'com.github.kenglxn.QRGen:android:2.2.0'
// Emojis
compile 'com.github.viirus:emoji-lib:0.0.3.2'
// Markdown
compile 'com.commonsware.cwac:anddown:0.2.4'
// About View for all dependent Libraries, we are using
compile('com.mikepenz:aboutlibraries:5.7.1@aar') {
transitive = true
}
// a better fab alternative
compile 'com.github.clans:fab:1.6.4'
// ORM
apt 'com.raizlabs.android:DBFlow-Compiler:2.2.1'
compile "com.raizlabs.android:DBFlow-Core:2.2.1"
compile "com.raizlabs.android:DBFlow:2.2.1"
//Eventbus
compile 'org.greenrobot:eventbus:3.0.0'
// IAP Handling / Verification
compile 'org.solovyev.android:checkout:0.7.5@aar'
//Facebook
compile('com.facebook.android:facebook-android-sdk:4.11.0') {
transitive = true
}
compile 'fr.avianey.com.viewpagerindicator:library:2.4.1@aar'
//RxJava
compile 'io.reactivex:rxandroid:1.2.1'
compile 'io.reactivex:rxjava:1.2.0'
//Analytics
compile 'com.amplitude:android-sdk:2.9.2'
// Fresco Image Management Library
compile('com.facebook.fresco:fresco:0.11.0') {
exclude module: 'bolts-android'
}
compile('com.facebook.fresco:animated-gif:0.11.0') {
exclude module: 'bolts-android'
}
//Tests
testCompile "junit:junit:4.10"
testCompile "org.assertj:assertj-core:1.7.0"
testCompile 'com.squareup.leakcanary:leakcanary-android-no-op:1.3.1'
testCompile "org.robolectric:robolectric:3.1"
testCompile 'org.robolectric:shadows-multidex:3.1'
testCompile "org.robolectric:shadows-support-v4:3.1"
testCompile "org.mockito:mockito-core:1.10.19"
//Leak Detection
debugCompile 'com.squareup.leakcanary:leakcanary-android:1.3.1'
releaseCompile 'com.squareup.leakcanary:leakcanary-android-no-op:1.3.1'
//Push Notifications
compile 'com.google.firebase:firebase-core:9.4.0'
compile 'com.google.firebase:firebase-messaging:9.4.0'
compile 'com.google.android.gms:play-services-auth:9.4.0'
}
android {
compileSdkVersion 24
buildToolsVersion "24.0.2"
defaultConfig {
applicationId "com.habitrpg.android.habitica"
}
lintOptions {
abortOnError false
}
signingConfigs {
release
}
buildTypes {
debug {
applicationIdSuffix ".debug"
debuggable true
multiDexEnabled true
// Disable fabric build ID generation for debug builds
ext.enableCrashlytics = false
resValue "string", "content_provider", "com.habitrpg.android.habitica.debug.fileprovider"
resValue "string", "app_name", "Habitica Debug"
}
release {
signingConfig signingConfigs.release
debuggable false
multiDexEnabled true
resValue "string", "content_provider", "com.habitrpg.android.habitica.fileprovider"
resValue "string", "app_name", "Habitica"
}
}
sourceSets {
main {
manifest.srcFile 'AndroidManifest.xml'
java.srcDirs = ['src/main/java']
resources.srcDirs = ['src/main/java']
aidl.srcDirs = ['src/main/java']
renderscript.srcDirs = ['src/main/java']
res.srcDirs = ['res']
assets.srcDirs = ['assets']
}
robolectric {
manifest.srcFile 'AndroidManifestTesting.xml'
java.srcDir file('src/test/java/')
res.srcDirs = ['res']
}
release.setRoot('build-types/release')
instrumentTest.setRoot('tests')
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
dexOptions {
preDexLibraries false
javaMaxHeapSize "4g" // Use gig increments depending on needs
incremental true
}
lintOptions {
disable 'UnusedResources'
}
}
def Properties props = new Properties()
def propFile = new File('signingrelease.properties')
if (propFile.canRead()) {
props.load(new FileInputStream(propFile))
if (props != null && props.containsKey('STORE_FILE') && props.containsKey('STORE_PASSWORD') &&
props.containsKey('KEY_ALIAS') && props.containsKey('KEY_PASSWORD')) {
android.signingConfigs.release.storeFile = file(props['STORE_FILE'])
android.signingConfigs.release.storePassword = props['STORE_PASSWORD']
android.signingConfigs.release.keyAlias = props['KEY_ALIAS']
android.signingConfigs.release.keyPassword = props['KEY_PASSWORD']
} else {
println 'signing.properties found but some entries are missing'
android.buildTypes.release.signingConfig = null
}
} else {
println 'signing.properties not found'
android.buildTypes.release.signingConfig = null
}
// Add Habitica Properties to buildConfigField
final File HRPG_PROPS_FILE = new File('habitica.properties')
if (HRPG_PROPS_FILE.canRead()) {
def Properties HRPG_PROPS = new Properties()
HRPG_PROPS.load(new FileInputStream(HRPG_PROPS_FILE))
if (HRPG_PROPS != null) {
android.buildTypes.all { buildType ->
HRPG_PROPS.any { property ->
buildType.buildConfigField "String", property.key, "\"${property.value}\""
}
}
} else {
throw new InvalidUserDataException('habitica.properties found but some entries are missing')
}
} else {
throw new MissingResourceException('habitica.properties not found')
}
// Add Habitica Resources to resources
final File HRPG_RES_FILE = new File('habitica.resources')
if (HRPG_RES_FILE.canRead()) {
def Properties HRPG_RES = new Properties()
HRPG_RES.load(new FileInputStream(HRPG_RES_FILE))
if (HRPG_RES != null) {
android.buildTypes.all { buildType ->
HRPG_RES.any { property ->
buildType.resValue "string", property.key, "\"${property.value}\""
}
}
} else {
throw new InvalidUserDataException('habitica.resources found but some entries are missing')
}
} else {
throw new MissingResourceException('habitica.resources not found')
}
tasks.whenTaskAdded { task ->
if (task.name.equals("lint")) {
task.enabled = false
}
}
apply plugin: 'com.getkeepsafe.dexcount'
apply plugin: 'com.android.application' //or apply plugin: 'java'
apply plugin: 'me.tatarka.retrolambda'
apply plugin: 'com.jakewharton.hugo'
apply plugin: 'com.google.gms.google-services'

View file

@ -23,7 +23,7 @@ import java.util.Map;
*/
public class PopupNotificationsManager {
private Map<String, String> seenNotifications;
private Map<String, Boolean> seenNotifications;
private APIHelper apiHelper;
private static PopupNotificationsManager instance;
@ -39,9 +39,9 @@ public class PopupNotificationsManager {
return instance;
}
private void displayNotification(Notification notification) {
public Boolean displayNotification(Notification notification) {
if (!notification.getType().equals("LOGIN_INCENTIVE")) {
return;
return false;
}
String title = notification.data.message;
@ -102,18 +102,31 @@ public class PopupNotificationsManager {
dialog.hide();
}
});
return true;
}
public void showNotificationDialog(final List<Notification> notifications) {
public Boolean showNotificationDialog(final List<Notification> notifications) {
if (notifications.size() == 0) {
return;
return false;
}
HabiticaApplication.currentActivity.runOnUiThread(() -> {
if ((HabiticaApplication.currentActivity).isFinishing()) return;
if (this.seenNotifications == null) {
this.seenNotifications = new HashMap<>();
}
for (Notification notification: notifications) {
if (this.seenNotifications.get(notification.getId()) != null) {
continue;
}
this.displayNotification(notification);
this.seenNotifications.put(notification.getId(), true);
}
});
return true;
}
}

View file

@ -1,19 +1,33 @@
package com.habitrpg.android.habitica.helpers;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.Context;
import android.os.Build;
import com.habitrpg.android.habitica.APIHelper;
import com.habitrpg.android.habitica.BuildConfig;
import com.habitrpg.android.habitica.HabiticaApplication;
import com.habitrpg.android.habitica.HostConfig;
import com.habitrpg.android.habitica.ui.activities.AboutActivity;
import com.habitrpg.android.habitica.ui.activities.BaseActivity;
import com.habitrpg.android.habitica.ui.activities.IntroActivity;
import com.habitrpg.android.habitica.ui.activities.MainActivity;
import com.magicmicky.habitrpgwrapper.lib.models.Notification;
import com.magicmicky.habitrpgwrapper.lib.models.UserAuthResponse;
import com.magicmicky.habitrpgwrapper.lib.models.notifications.NotificationData;
import com.magicmicky.habitrpgwrapper.lib.models.responses.HabitResponse;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.robolectric.Robolectric;
import org.robolectric.RobolectricGradleTestRunner;
import org.robolectric.Shadows;
import org.robolectric.annotation.Config;
import org.robolectric.shadows.ShadowAlertDialog;
import java.security.InvalidParameterException;
import java.util.ArrayList;
@ -24,6 +38,11 @@ import retrofit2.converter.gson.GsonConverterFactory;
import rx.observers.TestSubscriber;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
/**
* Created by krh12 on 12/9/2016.
@ -54,16 +73,84 @@ public class PopupNotificationsManagerTest {
List<Notification> notifications = new ArrayList<>();
PopupNotificationsManager popupNotificationsManager = PopupNotificationsManager.getInstance(apiHelper);
popupNotificationsManager.showNotificationDialog(notifications);
assertEquals("10 x 0 must be 0", 0, 10 * 0 );
AlertDialog alert =
ShadowAlertDialog.getLatestAlertDialog();
assertNull(alert);
}
@Test
// @TODO: Eventually, we should have a list of implemented notifications and only use those
public void itShouldNotDisplayNotificationsThatAreNotLoginIncentives() {}
public void itShouldNotDisplayNotificationsThatAreNotLoginIncentives() {
List<Notification> notifications = new ArrayList<>();
Notification notification = new Notification();
notification.setType("NOT_LOGIN_INCENTIVE");
notifications.add(notification);
PopupNotificationsManager popupNotificationsManager = PopupNotificationsManager.getInstance(apiHelper);
popupNotificationsManager.showNotificationDialog(notifications);
AlertDialog alert =
ShadowAlertDialog.getLatestAlertDialog();
assertNull(alert);
}
@Test
public void itShouldDisplayADialogueForANotification() {}
public void itShouldDisplayADialogueForANotification() {
Activity activity;
activity = Robolectric.buildActivity(Activity.class).create().get();
HabiticaApplication.currentActivity = activity;
String testTitle = "Test Title";
List<Notification> notifications = new ArrayList<>();
NotificationData notificationData = new NotificationData();
notificationData.message = testTitle;
Notification notification = new Notification();
notification.setType("LOGIN_INCENTIVE");
notification.data = notificationData;
notifications.add(notification);
final PopupNotificationsManager testClass = Mockito.mock(PopupNotificationsManager.class);
Mockito.when(testClass.displayNotification(notification)).thenReturn(true);
Mockito.when(testClass.showNotificationDialog(notifications)).thenCallRealMethod();
testClass.showNotificationDialog(notifications);
verify(testClass, times(1)).displayNotification(notification);
}
@Test
public void itShouldNotDisplayANotificationTwice() {}
public void itShouldNotDisplayANotificationTwice() {
Activity activity;
activity = Robolectric.buildActivity(Activity.class).create().get();
HabiticaApplication.currentActivity = activity;
String testTitle = "Test Title";
List<Notification> notifications = new ArrayList<>();
NotificationData notificationData = new NotificationData();
notificationData.message = testTitle;
Notification notification = new Notification();
notification.setType("LOGIN_INCENTIVE");
notification.data = notificationData;
notifications.add(notification);
notifications.add(notification);
final PopupNotificationsManager testClass = Mockito.mock(PopupNotificationsManager.class);
Mockito.when(testClass.displayNotification(notification)).thenReturn(true);
Mockito.when(testClass.showNotificationDialog(notifications)).thenCallRealMethod();
testClass.showNotificationDialog(notifications);
verify(testClass, times(1)).displayNotification(notification);
}
}