Merge branch 'release/1.6.0'
50
.gitignore
vendored
@@ -1,36 +1,22 @@
|
|||||||
#built application files
|
|
||||||
*.apk
|
|
||||||
*.ap_
|
*.ap_
|
||||||
|
*.apk
|
||||||
# files for the dex VM
|
|
||||||
*.dex
|
|
||||||
|
|
||||||
# Java class files
|
|
||||||
*.class
|
*.class
|
||||||
|
*.dex
|
||||||
# generated files
|
|
||||||
bin/
|
|
||||||
gen/
|
|
||||||
|
|
||||||
# Local configuration file (sdk path, etc)
|
|
||||||
local.properties
|
|
||||||
|
|
||||||
# Windows thumbnail db
|
|
||||||
Thumbs.db
|
|
||||||
|
|
||||||
# OSX files
|
|
||||||
.DS_Store
|
|
||||||
|
|
||||||
# Eclipse project files
|
|
||||||
.classpath
|
|
||||||
.project
|
|
||||||
|
|
||||||
# Android Studio
|
|
||||||
.idea
|
|
||||||
#.idea/workspace.xml - remove # and delete .idea if it better suit your needs.
|
|
||||||
.gradle
|
|
||||||
build/
|
|
||||||
*.iml
|
*.iml
|
||||||
|
*.local.*
|
||||||
|
*.swp
|
||||||
|
*.trace
|
||||||
|
*~
|
||||||
|
.DS_Store
|
||||||
|
.classpath
|
||||||
|
.gradle
|
||||||
|
.idea
|
||||||
|
.project
|
||||||
|
Thumbs.db
|
||||||
art/
|
art/
|
||||||
*.actual.png
|
bin/
|
||||||
|
build/
|
||||||
|
captures/
|
||||||
|
docs/
|
||||||
|
gen/
|
||||||
|
local.properties
|
||||||
|
|||||||
3
.gitmodules
vendored
@@ -1,3 +0,0 @@
|
|||||||
[submodule "libs/drag-sort-listview"]
|
|
||||||
path = libs/drag-sort-listview
|
|
||||||
url = https://github.com/iSoron/drag-sort-listview.git
|
|
||||||
24
CHANGELOG.md
@@ -1,5 +1,29 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
### 1.6.0 (Oct 10, 2016)
|
||||||
|
|
||||||
|
* Add option to make notifications sticky
|
||||||
|
* Add option to hide completed habits
|
||||||
|
* Display total number of repetitions for each habit
|
||||||
|
* Pebble integration: check/snooze habits from the watch
|
||||||
|
* Tasker/Locale integration: allow third-party apps to add checkmarks
|
||||||
|
* Export an unified CSV file, with checkmarks for all the habits
|
||||||
|
* Increase width of name column according to screen size
|
||||||
|
* Stop showing reminders for archived habits
|
||||||
|
* Add Danish, Dutch, Greek, Hindi and Portuguese (PT) translations
|
||||||
|
* Other minor fixes and enhancements
|
||||||
|
|
||||||
|
### 1.5.6 (Jun 19, 2016)
|
||||||
|
|
||||||
|
* Fix bug that prevented checkmark widget from working
|
||||||
|
|
||||||
|
### 1.5.5 (Jun 19, 2016)
|
||||||
|
|
||||||
|
* Fix bug that prevented check button on notification to work sometimes
|
||||||
|
* Fix bug that caused back button to apparently erase some checkmarks
|
||||||
|
* Complete French translation
|
||||||
|
* Add Croatian and Slovenian translations
|
||||||
|
|
||||||
### 1.5.4 (May 29, 2016)
|
### 1.5.4 (May 29, 2016)
|
||||||
|
|
||||||
* Fix crash upon opening settings screen in some phones
|
* Fix crash upon opening settings screen in some phones
|
||||||
|
|||||||
141
NOTICE.md
@@ -59,28 +59,6 @@ under the SIL OFL 1.1.
|
|||||||
requirement for fonts to remain under this license does not apply
|
requirement for fonts to remain under this license does not apply
|
||||||
to any document created using the fonts or their derivatives.
|
to any document created using the fonts or their derivatives.
|
||||||
|
|
||||||
|
|
||||||
### DragSortListView
|
|
||||||
|
|
||||||
<https://github.com/bauerca/drag-sort-listview>
|
|
||||||
|
|
||||||
A subclass of the Android ListView component that enables drag
|
|
||||||
and drop re-ordering of list items.
|
|
||||||
|
|
||||||
Copyright 2012 Carl Bauer
|
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
you may not use this file except in compliance with the License.
|
|
||||||
You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
||||||
|
|
||||||
### Material Design Icons
|
### Material Design Icons
|
||||||
|
|
||||||
<https://github.com/google/material-design-icons>
|
<https://github.com/google/material-design-icons>
|
||||||
@@ -108,3 +86,122 @@ Extended linear layout that wrap its content when there is no place in the curre
|
|||||||
WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
License for the specific language governing permissions and limitations
|
License for the specific language governing permissions and limitations
|
||||||
under the License.
|
under the License.
|
||||||
|
|
||||||
|
### Dagger 2
|
||||||
|
|
||||||
|
<https://github.com/google/dagger>
|
||||||
|
|
||||||
|
A fast dependency injector for Android and Java.
|
||||||
|
|
||||||
|
Copyright 2012 Square, Inc.
|
||||||
|
Copyright 2012 Google, Inc.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
|
||||||
|
### AutoFactory
|
||||||
|
|
||||||
|
<https://github.com/google/auto/tree/master/factory>
|
||||||
|
|
||||||
|
A source code generator for JSR-330-compatible factories.
|
||||||
|
|
||||||
|
Copyright 2013 Google, Inc.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
|
||||||
|
### Retrolambda
|
||||||
|
|
||||||
|
<https://github.com/orfjackal/retrolambda>
|
||||||
|
|
||||||
|
Backport of Java 8's lambda expressions to Java 7, 6 and 5
|
||||||
|
|
||||||
|
Copyright (c) 2013-2016 Esko Luontola and other Retrolambda contributors
|
||||||
|
This software is released under the Apache License 2.0.
|
||||||
|
The license text is at http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
### PebbleKit SDK
|
||||||
|
|
||||||
|
<https://github.com/pebble/pebble-android-sdk/>
|
||||||
|
|
||||||
|
Android PebbleKit SDK to talk to the Pebble via Bluetooth
|
||||||
|
|
||||||
|
The MIT License (MIT)
|
||||||
|
Copyright (c) 2014 - 2015 Pebble Technology
|
||||||
|
|
||||||
|
### AppIntro
|
||||||
|
|
||||||
|
<https://github.com/PaoloRotolo/AppIntro>
|
||||||
|
|
||||||
|
Make a cool intro for your Android app.
|
||||||
|
|
||||||
|
Copyright 2015 Paolo Rotolo
|
||||||
|
Copyright 2016 Maximilian Narr
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
|
||||||
|
### ButterKnife
|
||||||
|
|
||||||
|
<https://github.com/JakeWharton/butterknife>
|
||||||
|
|
||||||
|
Bind Android views and callbacks to fields and methods
|
||||||
|
|
||||||
|
Copyright 2013 Jake Wharton
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
|
||||||
|
### opencsv
|
||||||
|
|
||||||
|
<http://opencsv.sourceforge.net/>
|
||||||
|
|
||||||
|
Opencsv is a very simple csv (comma-separated values) parser library for Java.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
|||||||
41
README.md
@@ -1,10 +1,13 @@
|
|||||||
# Loop Habit Tracker
|
# Loop Habit Tracker
|
||||||
|
|
||||||
<a href="https://circleci.com/gh/iSoron/uhabits/tree/dev">
|
<a href="https://circleci.com/gh/iSoron/uhabits/tree/dev">
|
||||||
<img src="https://img.shields.io/circleci/project/iSoron/uhabits/dev.svg">
|
<img src="https://img.shields.io/circleci/project/iSoron/uhabits/dev.svg">
|
||||||
</a>
|
</a>
|
||||||
|
<!--
|
||||||
<a href="https://codecov.io/github/iSoron/uhabits?branch=dev">
|
<a href="https://codecov.io/github/iSoron/uhabits?branch=dev">
|
||||||
<img src="https://img.shields.io/codecov/c/github/iSoron/uhabits.svg" alt="Coverage via Codecov" />
|
<img src="https://img.shields.io/codecov/c/github/iSoron/uhabits.svg" alt="Coverage via Codecov" />
|
||||||
</a>
|
</a>
|
||||||
|
-->
|
||||||
|
|
||||||
Loop is a simple Android app that helps you create and maintain good habits,
|
Loop is a simple Android app that helps you create and maintain good habits,
|
||||||
allowing you to achieve your long-term goals. Detailed graphs and statistics
|
allowing you to achieve your long-term goals. Detailed graphs and statistics
|
||||||
@@ -16,6 +19,15 @@ source.
|
|||||||
<a href="http://f-droid.org/app/org.isoron.uhabits"><img alt="Git if on F-Droid" src="http://i.imgur.com/baSPE7X.png" height="75px"/></a>
|
<a href="http://f-droid.org/app/org.isoron.uhabits"><img alt="Git if on F-Droid" src="http://i.imgur.com/baSPE7X.png" height="75px"/></a>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
|
## Screenshots
|
||||||
|
|
||||||
|
[![Main screen][screen1th]][screen1]
|
||||||
|
[![Edit habit][screen2th]][screen2]
|
||||||
|
[![Habit strength][screen3th]][screen3]
|
||||||
|
[![Habit history and streaks][screen4th]][screen4]
|
||||||
|
[![Widgets][screen5th]][screen5]
|
||||||
|
[![Night mode][screen6th]][screen6]
|
||||||
|
|
||||||
## Features
|
## Features
|
||||||
|
|
||||||
* **Simple, beautiful and modern interface.** Loop has a minimalistic interface
|
* **Simple, beautiful and modern interface.** Loop has a minimalistic interface
|
||||||
@@ -47,21 +59,12 @@ source.
|
|||||||
and there will never be. The complete source code is available under the
|
and there will never be. The complete source code is available under the
|
||||||
GPLv3.
|
GPLv3.
|
||||||
|
|
||||||
## Screenshots
|
|
||||||
|
|
||||||
[![Main screen][screen1th]][screen1]
|
|
||||||
[![Edit habit][screen2th]][screen2]
|
|
||||||
[![Habit strength][screen3th]][screen3]
|
|
||||||
[![Habit history and streaks][screen4th]][screen4]
|
|
||||||
[![Widgets][screen5th]][screen5]
|
|
||||||
[![Night mode][screen6th]][screen6]
|
|
||||||
|
|
||||||
## Installing
|
## Installing
|
||||||
|
|
||||||
The easiest way to install Loop is through the [Google Play Store][playstore] or [F-Droid][fdroid].
|
The easiest way to install Loop is through the [Google Play Store][playstore] or [F-Droid][fdroid].
|
||||||
You may also download and install the APK from the [releases page][releases];
|
You may also download and install the APK from the [releases page][releases];
|
||||||
note, however, that the app will not be updated automatically. To build this
|
note, however, that the app will not be updated automatically. To build this
|
||||||
app from the source code, see [building instructions][build].
|
app from the source code, see [build instructions][build].
|
||||||
|
|
||||||
## Contributing
|
## Contributing
|
||||||
|
|
||||||
@@ -89,14 +92,18 @@ contribute, even if you are not a software developer.
|
|||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
This program is free software: you can redistribute it and/or modify it
|
<img align="right" src="https://www.gnu.org/graphics/gplv3-88x31.png">
|
||||||
under the terms of the GNU General Public License as published by the Free
|
|
||||||
Software Foundation, either version 3 of the License, or (at your option)
|
|
||||||
any later version.
|
|
||||||
|
|
||||||
This program is distributed in the hope that it will be useful, but WITHOUT
|
Copyright (C) 2016 Álinson Santos Xavier <isoron@gmail.com>
|
||||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
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.
|
more details.
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License along
|
You should have received a copy of the GNU General Public License along
|
||||||
|
|||||||
@@ -1,4 +1,7 @@
|
|||||||
apply plugin: 'com.android.application'
|
apply plugin: 'com.android.application'
|
||||||
|
apply plugin: 'com.neenbedankt.android-apt'
|
||||||
|
apply plugin: 'me.tatarka.retrolambda'
|
||||||
|
apply plugin: 'jacoco'
|
||||||
|
|
||||||
android {
|
android {
|
||||||
compileSdkVersion 23
|
compileSdkVersion 23
|
||||||
@@ -13,7 +16,7 @@ android {
|
|||||||
buildConfigField "String", "databaseFilename", "\"uhabits.db\""
|
buildConfigField "String", "databaseFilename", "\"uhabits.db\""
|
||||||
|
|
||||||
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
|
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
|
||||||
//testInstrumentationRunnerArgument "size", "small"
|
testInstrumentationRunnerArgument "size", "medium"
|
||||||
}
|
}
|
||||||
|
|
||||||
buildTypes {
|
buildTypes {
|
||||||
@@ -29,23 +32,59 @@ android {
|
|||||||
lintOptions {
|
lintOptions {
|
||||||
checkReleaseBuilds false
|
checkReleaseBuilds false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
compileOptions {
|
||||||
|
targetCompatibility 1.8
|
||||||
|
sourceCompatibility 1.8
|
||||||
|
}
|
||||||
|
|
||||||
|
testOptions {
|
||||||
|
unitTests.all {
|
||||||
|
testLogging {
|
||||||
|
events "passed", "skipped", "failed", "standardOut", "standardError"
|
||||||
|
outputs.upToDateWhen { false }
|
||||||
|
showStandardStreams = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
compile 'com.android.support:support-v4:23.3.0'
|
|
||||||
|
androidTestApt 'com.google.dagger:dagger-compiler:2.2'
|
||||||
|
|
||||||
|
androidTestCompile 'com.android.support:support-annotations:23.3.0'
|
||||||
|
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'
|
||||||
|
|
||||||
|
apt 'com.google.dagger:dagger-compiler:2.2'
|
||||||
|
apt 'com.jakewharton:butterknife-compiler:8.0.1'
|
||||||
|
|
||||||
compile 'com.android.support:appcompat-v7:23.3.0'
|
compile 'com.android.support:appcompat-v7:23.3.0'
|
||||||
compile 'com.android.support:design:23.3.0'
|
compile 'com.android.support:design:23.3.0'
|
||||||
compile 'com.android.support:preference-v14:23.3.0'
|
compile 'com.android.support:preference-v14:23.3.0'
|
||||||
|
compile 'com.android.support:support-v4:23.3.0'
|
||||||
|
compile 'com.getpebble:pebblekit:3.0.0'
|
||||||
compile 'com.github.paolorotolo:appintro:3.4.0'
|
compile 'com.github.paolorotolo:appintro:3.4.0'
|
||||||
compile 'org.apmem.tools:layouts:1.10@aar'
|
compile 'com.google.auto.factory:auto-factory:1.0-beta3'
|
||||||
compile 'com.opencsv:opencsv:3.7'
|
compile 'com.google.dagger:dagger:2.2'
|
||||||
|
compile 'com.jakewharton:butterknife:8.0.1'
|
||||||
compile 'com.michaelpardo:activeandroid:3.1.0-SNAPSHOT'
|
compile 'com.michaelpardo:activeandroid:3.1.0-SNAPSHOT'
|
||||||
|
compile 'com.opencsv:opencsv:3.7'
|
||||||
|
compile 'org.apmem.tools:layouts:1.10@aar'
|
||||||
|
compile 'org.jetbrains:annotations-java5:15.0'
|
||||||
|
|
||||||
compile project(':libs:drag-sort-listview:library')
|
provided 'javax.annotation:jsr250-api:1.0'
|
||||||
|
|
||||||
androidTestCompile 'com.android.support:support-annotations:23.3.0'
|
testApt 'com.google.dagger:dagger-compiler:2.2'
|
||||||
androidTestCompile 'com.android.support.test:runner:0.5'
|
|
||||||
androidTestCompile 'com.android.support.test:rules:0.5'
|
testCompile 'junit:junit:4.12'
|
||||||
|
testCompile 'org.hamcrest:hamcrest-library:1.3'
|
||||||
|
testCompile 'org.mockito:mockito-core:1.10.19'
|
||||||
|
|
||||||
androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.1') {
|
androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.1') {
|
||||||
exclude group: 'com.android.support'
|
exclude group: 'com.android.support'
|
||||||
@@ -60,13 +99,44 @@ dependencies {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
retrolambda {
|
||||||
task grantAnimationPermission(type: Exec, dependsOn: 'installDebug') {
|
defaultMethods true
|
||||||
commandLine "adb shell pm grant org.isoron.uhabits android.permission.SET_ANIMATION_SCALE".split(' ')
|
|
||||||
}
|
}
|
||||||
|
|
||||||
tasks.whenTaskAdded { task ->
|
jacoco {
|
||||||
if (task.name.startsWith('connected')) {
|
toolVersion = "0.7.4.201502262128"
|
||||||
task.dependsOn grantAnimationPermission
|
}
|
||||||
|
|
||||||
|
task coverageReport(type: JacocoReport, dependsOn: ['testDebugUnitTest']) {
|
||||||
|
|
||||||
|
jacocoClasspath = configurations['androidJacocoAnt']
|
||||||
|
|
||||||
|
reports {
|
||||||
|
html.enabled = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def excludes = [
|
||||||
|
'**/R.class',
|
||||||
|
'**/R$*.class',
|
||||||
|
'**/BuildConfig.*',
|
||||||
|
'**/Manifest*',
|
||||||
|
'**/*Test*.*',
|
||||||
|
'**/*$Lambda$*',
|
||||||
|
'**/*$ViewBinder*',
|
||||||
|
'**/*MembersInjector*',
|
||||||
|
'**/*_Provide*',
|
||||||
|
'**/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)
|
||||||
}
|
}
|
||||||
3
app/proguard-rules.txt
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
-dontwarn java.beans.**
|
||||||
|
-dontwarn java.lang.**
|
||||||
|
-dontobfuscate
|
||||||
|
Before Width: | Height: | Size: 8.6 KiB |
|
Before Width: | Height: | Size: 8.5 KiB |
|
Before Width: | Height: | Size: 17 KiB |
|
Before Width: | Height: | Size: 8.6 KiB |
|
Before Width: | Height: | Size: 5.2 KiB |
|
Before Width: | Height: | Size: 3.9 KiB |
|
Before Width: | Height: | Size: 13 KiB |
|
Before Width: | Height: | Size: 8.3 KiB After Width: | Height: | Size: 8.3 KiB |
|
Before Width: | Height: | Size: 6.3 KiB After Width: | Height: | Size: 6.3 KiB |
|
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 15 KiB |
|
Before Width: | Height: | Size: 8.3 KiB After Width: | Height: | Size: 8.3 KiB |
|
Before Width: | Height: | Size: 58 KiB After Width: | Height: | Size: 58 KiB |
|
Before Width: | Height: | Size: 54 KiB After Width: | Height: | Size: 54 KiB |
|
Before Width: | Height: | Size: 31 KiB After Width: | Height: | Size: 31 KiB |
|
Before Width: | Height: | Size: 53 KiB After Width: | Height: | Size: 53 KiB |
|
Before Width: | Height: | Size: 8.2 KiB After Width: | Height: | Size: 8.2 KiB |
|
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 15 KiB |
|
Before Width: | Height: | Size: 25 KiB After Width: | Height: | Size: 25 KiB |
|
Before Width: | Height: | Size: 27 KiB After Width: | Height: | Size: 27 KiB |
|
Before Width: | Height: | Size: 19 KiB After Width: | Height: | Size: 19 KiB |
|
Before Width: | Height: | Size: 25 KiB After Width: | Height: | Size: 25 KiB |
|
Before Width: | Height: | Size: 21 KiB After Width: | Height: | Size: 21 KiB |
|
Before Width: | Height: | Size: 19 KiB After Width: | Height: | Size: 19 KiB |
|
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 16 KiB |
|
Before Width: | Height: | Size: 2.5 KiB After Width: | Height: | Size: 2.5 KiB |
|
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 16 KiB |
|
After Width: | Height: | Size: 551 B |
|
After Width: | Height: | Size: 505 B |
|
After Width: | Height: | Size: 559 B |
|
After Width: | Height: | Size: 1.4 KiB |
|
After Width: | Height: | Size: 5.0 KiB |
|
After Width: | Height: | Size: 5.4 KiB |
|
After Width: | Height: | Size: 5.1 KiB |
BIN
app/src/androidTest/assets/views/habits/list/HintView/render.png
Normal file
|
After Width: | Height: | Size: 14 KiB |
|
After Width: | Height: | Size: 17 KiB |
|
After Width: | Height: | Size: 35 KiB |
|
After Width: | Height: | Size: 11 KiB |
|
After Width: | Height: | Size: 23 KiB |
|
After Width: | Height: | Size: 27 KiB |
|
After Width: | Height: | Size: 10 KiB |
|
After Width: | Height: | Size: 7.9 KiB |
|
After Width: | Height: | Size: 8.5 KiB |
|
After Width: | Height: | Size: 9.4 KiB |
|
After Width: | Height: | Size: 17 KiB |
|
After Width: | Height: | Size: 9.6 KiB |
|
After Width: | Height: | Size: 19 KiB |
|
After Width: | Height: | Size: 36 KiB |
BIN
app/src/androidTest/assets/views/widgets/ScoreWidget/render.png
Normal file
|
After Width: | Height: | Size: 19 KiB |
BIN
app/src/androidTest/assets/views/widgets/StreakWidget/render.png
Normal file
|
After Width: | Height: | Size: 35 KiB |
@@ -0,0 +1,36 @@
|
|||||||
|
/*
|
||||||
|
* 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.models.sqlite.*;
|
||||||
|
import org.isoron.uhabits.tasks.*;
|
||||||
|
|
||||||
|
import dagger.*;
|
||||||
|
|
||||||
|
@AppScope
|
||||||
|
@Component(modules = {
|
||||||
|
AppModule.class, SingleThreadTaskRunner.class, SQLModelFactory.class
|
||||||
|
})
|
||||||
|
public interface AndroidTestComponent extends AppComponent
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
133
app/src/androidTest/java/org/isoron/uhabits/BaseAndroidTest.java
Normal file
@@ -0,0 +1,133 @@
|
|||||||
|
/*
|
||||||
|
* 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.os.*;
|
||||||
|
import android.support.annotation.*;
|
||||||
|
import android.support.test.*;
|
||||||
|
|
||||||
|
import org.isoron.uhabits.models.*;
|
||||||
|
import org.isoron.uhabits.preferences.*;
|
||||||
|
import org.isoron.uhabits.tasks.*;
|
||||||
|
import org.isoron.uhabits.utils.*;
|
||||||
|
import org.junit.*;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.concurrent.*;
|
||||||
|
|
||||||
|
import static junit.framework.Assert.*;
|
||||||
|
import static org.hamcrest.MatcherAssert.*;
|
||||||
|
import static org.hamcrest.Matchers.*;
|
||||||
|
|
||||||
|
public class BaseAndroidTest
|
||||||
|
{
|
||||||
|
// 8:00am, January 25th, 2015 (UTC)
|
||||||
|
public static final long FIXED_LOCAL_TIME = 1422172800000L;
|
||||||
|
|
||||||
|
private static boolean isLooperPrepared;
|
||||||
|
|
||||||
|
protected Context testContext;
|
||||||
|
|
||||||
|
protected Context targetContext;
|
||||||
|
|
||||||
|
protected Preferences prefs;
|
||||||
|
|
||||||
|
protected HabitList habitList;
|
||||||
|
|
||||||
|
protected TaskRunner taskRunner;
|
||||||
|
|
||||||
|
protected HabitLogger logger;
|
||||||
|
|
||||||
|
protected HabitFixtures fixtures;
|
||||||
|
|
||||||
|
protected CountDownLatch latch;
|
||||||
|
|
||||||
|
protected AndroidTestComponent component;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setUp()
|
||||||
|
{
|
||||||
|
if (!isLooperPrepared)
|
||||||
|
{
|
||||||
|
Looper.prepare();
|
||||||
|
isLooperPrepared = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
targetContext = InstrumentationRegistry.getTargetContext();
|
||||||
|
testContext = InstrumentationRegistry.getContext();
|
||||||
|
|
||||||
|
DateUtils.setFixedLocalTime(FIXED_LOCAL_TIME);
|
||||||
|
setTheme(R.style.AppBaseTheme);
|
||||||
|
|
||||||
|
component = DaggerAndroidTestComponent
|
||||||
|
.builder()
|
||||||
|
.appModule(new AppModule(targetContext.getApplicationContext()))
|
||||||
|
.build();
|
||||||
|
|
||||||
|
HabitsApplication.setComponent(component);
|
||||||
|
prefs = component.getPreferences();
|
||||||
|
habitList = component.getHabitList();
|
||||||
|
taskRunner = component.getTaskRunner();
|
||||||
|
logger = component.getHabitsLogger();
|
||||||
|
|
||||||
|
ModelFactory modelFactory = component.getModelFactory();
|
||||||
|
fixtures = new HabitFixtures(modelFactory, habitList);
|
||||||
|
|
||||||
|
latch = new CountDownLatch(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
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(60, TimeUnit.SECONDS));
|
||||||
|
}
|
||||||
|
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,68 +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;
|
|
||||||
|
|
||||||
import android.content.Context;
|
|
||||||
import android.os.Build;
|
|
||||||
import android.os.Looper;
|
|
||||||
import android.support.test.InstrumentationRegistry;
|
|
||||||
|
|
||||||
import org.isoron.uhabits.helpers.DateHelper;
|
|
||||||
import org.isoron.uhabits.helpers.UIHelper;
|
|
||||||
import org.isoron.uhabits.tasks.BaseTask;
|
|
||||||
import org.junit.Before;
|
|
||||||
|
|
||||||
import java.util.concurrent.TimeoutException;
|
|
||||||
|
|
||||||
public class BaseTest
|
|
||||||
{
|
|
||||||
protected Context testContext;
|
|
||||||
protected Context targetContext;
|
|
||||||
private static boolean isLooperPrepared;
|
|
||||||
|
|
||||||
public static final long FIXED_LOCAL_TIME = 1422172800000L; // 8:00am, January 25th, 2015 (UTC)
|
|
||||||
|
|
||||||
@Before
|
|
||||||
public void setup()
|
|
||||||
{
|
|
||||||
if(!isLooperPrepared)
|
|
||||||
{
|
|
||||||
Looper.prepare();
|
|
||||||
isLooperPrepared = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
targetContext = InstrumentationRegistry.getTargetContext();
|
|
||||||
testContext = InstrumentationRegistry.getContext();
|
|
||||||
|
|
||||||
UIHelper.setFixedTheme(R.style.AppBaseTheme);
|
|
||||||
DateHelper.setFixedLocalTime(FIXED_LOCAL_TIME);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void waitForAsyncTasks() throws InterruptedException, TimeoutException
|
|
||||||
{
|
|
||||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN)
|
|
||||||
{
|
|
||||||
Thread.sleep(1000);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
BaseTask.waitForTasks(10000);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -17,47 +17,46 @@
|
|||||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.isoron.uhabits.unit.views;
|
package org.isoron.uhabits;
|
||||||
|
|
||||||
import android.graphics.Bitmap;
|
import android.graphics.*;
|
||||||
import android.graphics.BitmapFactory;
|
import android.os.*;
|
||||||
import android.os.SystemClock;
|
import android.support.annotation.*;
|
||||||
import android.view.GestureDetector;
|
import android.view.*;
|
||||||
import android.view.MotionEvent;
|
import android.widget.*;
|
||||||
import android.view.View;
|
|
||||||
|
|
||||||
import org.isoron.uhabits.BaseTest;
|
import org.isoron.uhabits.utils.*;
|
||||||
import org.isoron.uhabits.helpers.DatabaseHelper;
|
import org.isoron.uhabits.widgets.*;
|
||||||
import org.isoron.uhabits.helpers.UIHelper;
|
|
||||||
import org.isoron.uhabits.tasks.BaseTask;
|
|
||||||
import org.isoron.uhabits.views.HabitDataView;
|
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.*;
|
||||||
import java.io.FileOutputStream;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
|
|
||||||
import static junit.framework.Assert.fail;
|
import static android.view.View.MeasureSpec.*;
|
||||||
|
import static junit.framework.Assert.*;
|
||||||
|
|
||||||
public class ViewTest extends BaseTest
|
public class BaseViewTest extends BaseAndroidTest
|
||||||
{
|
{
|
||||||
protected static final double SIMILARITY_CUTOFF = 0.09;
|
protected static final double DEFAULT_SIMILARITY_CUTOFF = 0.09;
|
||||||
|
|
||||||
public static final int HISTOGRAM_BIN_SIZE = 8;
|
public static final int HISTOGRAM_BIN_SIZE = 8;
|
||||||
|
|
||||||
protected void measureView(int width, int height, View view)
|
private double similarityCutoff;
|
||||||
{
|
|
||||||
int specWidth = View.MeasureSpec.makeMeasureSpec(width, View.MeasureSpec.EXACTLY);
|
|
||||||
int specHeight = View.MeasureSpec.makeMeasureSpec(height, View.MeasureSpec.EXACTLY);
|
|
||||||
|
|
||||||
view.measure(specWidth, specHeight);
|
@Override
|
||||||
view.layout(0, 0, view.getMeasuredWidth(), view.getMeasuredHeight());
|
public void setUp()
|
||||||
|
{
|
||||||
|
super.setUp();
|
||||||
|
similarityCutoff = DEFAULT_SIMILARITY_CUTOFF;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void assertRenders(View view, String expectedImagePath) throws IOException
|
protected void assertRenders(View view, String expectedImagePath)
|
||||||
|
throws IOException
|
||||||
{
|
{
|
||||||
StringBuilder errorMessage = new StringBuilder();
|
StringBuilder errorMessage = new StringBuilder();
|
||||||
expectedImagePath = getVersionedViewAssetPath(expectedImagePath);
|
expectedImagePath = getVersionedViewAssetPath(expectedImagePath);
|
||||||
|
|
||||||
|
if (view.isLayoutRequested()) measureView(view, view.getMeasuredWidth(),
|
||||||
|
view.getMeasuredHeight());
|
||||||
|
|
||||||
view.setDrawingCacheEnabled(true);
|
view.setDrawingCacheEnabled(true);
|
||||||
view.buildDrawingCache();
|
view.buildDrawingCache();
|
||||||
Bitmap actual = view.getDrawingCache();
|
Bitmap actual = view.getDrawingCache();
|
||||||
@@ -65,12 +64,14 @@ public class ViewTest extends BaseTest
|
|||||||
|
|
||||||
int width = actual.getWidth();
|
int width = actual.getWidth();
|
||||||
int height = actual.getHeight();
|
int height = actual.getHeight();
|
||||||
Bitmap scaledExpected = Bitmap.createScaledBitmap(expected, width, height, true);
|
Bitmap scaledExpected =
|
||||||
|
Bitmap.createScaledBitmap(expected, width, height, true);
|
||||||
|
|
||||||
double distance;
|
double distance;
|
||||||
boolean similarEnough = true;
|
boolean similarEnough = true;
|
||||||
|
|
||||||
if ((distance = compareHistograms(getHistogram(actual), getHistogram(scaledExpected))) > SIMILARITY_CUTOFF)
|
if ((distance = compareHistograms(getHistogram(actual),
|
||||||
|
getHistogram(scaledExpected))) > similarityCutoff)
|
||||||
{
|
{
|
||||||
similarEnough = false;
|
similarEnough = false;
|
||||||
errorMessage.append(String.format(
|
errorMessage.append(String.format(
|
||||||
@@ -78,25 +79,125 @@ public class ViewTest extends BaseTest
|
|||||||
distance));
|
distance));
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!similarEnough)
|
if (!similarEnough)
|
||||||
{
|
{
|
||||||
saveBitmap(expectedImagePath, ".expected", scaledExpected);
|
saveBitmap(expectedImagePath, ".expected", scaledExpected);
|
||||||
String path = saveBitmap(expectedImagePath, "", actual);
|
String path = saveBitmap(expectedImagePath, "", actual);
|
||||||
errorMessage.append(String.format("Actual rendered image " + "saved to %s", path));
|
errorMessage.append(
|
||||||
|
String.format("Actual rendered image saved to %s", path));
|
||||||
fail(errorMessage.toString());
|
fail(errorMessage.toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
actual.recycle();
|
|
||||||
expected.recycle();
|
expected.recycle();
|
||||||
scaledExpected.recycle();
|
scaledExpected.recycle();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@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 int dpToPixels(int dp)
|
||||||
|
{
|
||||||
|
return (int) InterfaceUtils.dpToPixels(targetContext, dp);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void measureView(View view, int width, int height)
|
||||||
|
{
|
||||||
|
int specWidth = makeMeasureSpec(width, View.MeasureSpec.EXACTLY);
|
||||||
|
int specHeight = makeMeasureSpec(height, View.MeasureSpec.EXACTLY);
|
||||||
|
|
||||||
|
view.setLayoutParams(new ViewGroup.LayoutParams(width, height));
|
||||||
|
view.measure(specWidth, specHeight);
|
||||||
|
view.layout(0, 0, view.getMeasuredWidth(), view.getMeasuredHeight());
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void setSimilarityCutoff(double similarityCutoff)
|
||||||
|
{
|
||||||
|
this.similarityCutoff = similarityCutoff;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void skipAnimation(View view)
|
||||||
|
{
|
||||||
|
ViewPropertyAnimator animator = view.animate();
|
||||||
|
animator.setDuration(0);
|
||||||
|
animator.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void tap(GestureDetector.OnGestureListener view, int x, int y)
|
||||||
|
throws InterruptedException
|
||||||
|
{
|
||||||
|
long now = SystemClock.uptimeMillis();
|
||||||
|
MotionEvent e =
|
||||||
|
MotionEvent.obtain(now, now, MotionEvent.ACTION_UP, dpToPixels(x),
|
||||||
|
dpToPixels(y), 0);
|
||||||
|
view.onSingleTapUp(e);
|
||||||
|
e.recycle();
|
||||||
|
}
|
||||||
|
|
||||||
|
private double compareHistograms(int[][] actualHistogram,
|
||||||
|
int[][] expectedHistogram)
|
||||||
|
{
|
||||||
|
long diff = 0;
|
||||||
|
long total = 0;
|
||||||
|
|
||||||
|
for (int i = 0; i < 256 / HISTOGRAM_BIN_SIZE; i++)
|
||||||
|
{
|
||||||
|
diff += Math.abs(actualHistogram[0][i] - expectedHistogram[0][i]);
|
||||||
|
diff += Math.abs(actualHistogram[1][i] - expectedHistogram[1][i]);
|
||||||
|
diff += Math.abs(actualHistogram[2][i] - expectedHistogram[2][i]);
|
||||||
|
diff += Math.abs(actualHistogram[3][i] - expectedHistogram[3][i]);
|
||||||
|
|
||||||
|
total += actualHistogram[0][i];
|
||||||
|
total += actualHistogram[1][i];
|
||||||
|
total += actualHistogram[2][i];
|
||||||
|
total += actualHistogram[3][i];
|
||||||
|
}
|
||||||
|
|
||||||
|
return (double) diff / total / 2;
|
||||||
|
}
|
||||||
|
|
||||||
private Bitmap getBitmapFromAssets(String path) throws IOException
|
private Bitmap getBitmapFromAssets(String path) throws IOException
|
||||||
{
|
{
|
||||||
InputStream stream = testContext.getAssets().open(path);
|
InputStream stream = testContext.getAssets().open(path);
|
||||||
return BitmapFactory.decodeStream(stream);
|
return BitmapFactory.decodeStream(stream);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private int[][] getHistogram(Bitmap bitmap)
|
||||||
|
{
|
||||||
|
int histogram[][] = new int[4][256 / HISTOGRAM_BIN_SIZE];
|
||||||
|
|
||||||
|
for (int x = 0; x < bitmap.getWidth(); x++)
|
||||||
|
{
|
||||||
|
for (int y = 0; y < bitmap.getHeight(); y++)
|
||||||
|
{
|
||||||
|
int color = bitmap.getPixel(x, y);
|
||||||
|
int[] argb = new int[]{
|
||||||
|
(color >> 24) & 0xff, //alpha
|
||||||
|
(color >> 16) & 0xff, //red
|
||||||
|
(color >> 8) & 0xff, //green
|
||||||
|
(color) & 0xff //blue
|
||||||
|
};
|
||||||
|
|
||||||
|
histogram[0][argb[0] / HISTOGRAM_BIN_SIZE]++;
|
||||||
|
histogram[1][argb[1] / HISTOGRAM_BIN_SIZE]++;
|
||||||
|
histogram[2][argb[2] / HISTOGRAM_BIN_SIZE]++;
|
||||||
|
histogram[3][argb[3] / HISTOGRAM_BIN_SIZE]++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return histogram;
|
||||||
|
}
|
||||||
|
|
||||||
private String getVersionedViewAssetPath(String path)
|
private String getVersionedViewAssetPath(String path)
|
||||||
{
|
{
|
||||||
String result = null;
|
String result = null;
|
||||||
@@ -115,8 +216,7 @@ public class ViewTest extends BaseTest
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(result == null)
|
if (result == null) result = "views/" + path;
|
||||||
result = "views/" + path;
|
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@@ -124,16 +224,18 @@ public class ViewTest extends BaseTest
|
|||||||
private String saveBitmap(String filename, String suffix, Bitmap bitmap)
|
private String saveBitmap(String filename, String suffix, Bitmap bitmap)
|
||||||
throws IOException
|
throws IOException
|
||||||
{
|
{
|
||||||
File dir = DatabaseHelper.getSDCardDir("test-screenshots");
|
File dir = FileUtils.getSDCardDir("test-screenshots");
|
||||||
if(dir == null) dir = DatabaseHelper.getFilesDir("test-screenshots");
|
if (dir == null) dir = FileUtils.getFilesDir("test-screenshots");
|
||||||
if(dir == null) throw new RuntimeException("Could not find suitable dir for screenshots");
|
if (dir == null) throw new RuntimeException(
|
||||||
|
"Could not find suitable dir for screenshots");
|
||||||
|
|
||||||
filename = filename.replaceAll("\\.png$", suffix + ".png");
|
filename = filename.replaceAll("\\.png$", suffix + ".png");
|
||||||
String absolutePath = String.format("%s/%s", dir.getAbsolutePath(), filename);
|
String absolutePath =
|
||||||
|
String.format("%s/%s", dir.getAbsolutePath(), filename);
|
||||||
|
|
||||||
File parent = new File(absolutePath).getParentFile();
|
File parent = new File(absolutePath).getParentFile();
|
||||||
if(!parent.exists() && !parent.mkdirs())
|
if (!parent.exists() && !parent.mkdirs()) throw new RuntimeException(
|
||||||
throw new RuntimeException(String.format("Could not create dir: %s",
|
String.format("Could not create dir: %s",
|
||||||
parent.getAbsolutePath()));
|
parent.getAbsolutePath()));
|
||||||
|
|
||||||
FileOutputStream out = new FileOutputStream(absolutePath);
|
FileOutputStream out = new FileOutputStream(absolutePath);
|
||||||
@@ -141,86 +243,4 @@ public class ViewTest extends BaseTest
|
|||||||
|
|
||||||
return absolutePath;
|
return absolutePath;
|
||||||
}
|
}
|
||||||
|
|
||||||
private int[][] getHistogram(Bitmap bitmap)
|
|
||||||
{
|
|
||||||
int histogram[][] = new int[4][256 / HISTOGRAM_BIN_SIZE];
|
|
||||||
|
|
||||||
for(int x = 0; x < bitmap.getWidth(); x++)
|
|
||||||
{
|
|
||||||
for(int y = 0; y < bitmap.getHeight(); y++)
|
|
||||||
{
|
|
||||||
int color = bitmap.getPixel(x, y);
|
|
||||||
int[] argb = new int[]{
|
|
||||||
(color >> 24) & 0xff, //alpha
|
|
||||||
(color >> 16) & 0xff, //red
|
|
||||||
(color >> 8) & 0xff, //green
|
|
||||||
(color ) & 0xff //blue
|
|
||||||
};
|
|
||||||
|
|
||||||
histogram[0][argb[0] / HISTOGRAM_BIN_SIZE]++;
|
|
||||||
histogram[1][argb[1] / HISTOGRAM_BIN_SIZE]++;
|
|
||||||
histogram[2][argb[2] / HISTOGRAM_BIN_SIZE]++;
|
|
||||||
histogram[3][argb[3] / HISTOGRAM_BIN_SIZE]++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return histogram;
|
|
||||||
}
|
|
||||||
|
|
||||||
private double compareHistograms(int[][] actualHistogram, int[][] expectedHistogram)
|
|
||||||
{
|
|
||||||
long diff = 0;
|
|
||||||
long total = 0;
|
|
||||||
|
|
||||||
for(int i = 0; i < 256 / HISTOGRAM_BIN_SIZE; i ++)
|
|
||||||
{
|
|
||||||
diff += Math.abs(actualHistogram[0][i] - expectedHistogram[0][i]);
|
|
||||||
diff += Math.abs(actualHistogram[1][i] - expectedHistogram[1][i]);
|
|
||||||
diff += Math.abs(actualHistogram[2][i] - expectedHistogram[2][i]);
|
|
||||||
diff += Math.abs(actualHistogram[3][i] - expectedHistogram[3][i]);
|
|
||||||
|
|
||||||
total += actualHistogram[0][i];
|
|
||||||
total += actualHistogram[1][i];
|
|
||||||
total += actualHistogram[2][i];
|
|
||||||
total += actualHistogram[3][i];
|
|
||||||
}
|
|
||||||
|
|
||||||
return (double) diff / total / 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected int dpToPixels(int dp)
|
|
||||||
{
|
|
||||||
return (int) UIHelper.dpToPixels(targetContext, dp);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void tap(GestureDetector.OnGestureListener view, int x, int y) throws InterruptedException
|
|
||||||
{
|
|
||||||
long now = SystemClock.uptimeMillis();
|
|
||||||
MotionEvent e = MotionEvent.obtain(now, now, MotionEvent.ACTION_UP, dpToPixels(x),
|
|
||||||
dpToPixels(y), 0);
|
|
||||||
view.onSingleTapUp(e);
|
|
||||||
e.recycle();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void refreshData(final HabitDataView view)
|
|
||||||
{
|
|
||||||
new BaseTask()
|
|
||||||
{
|
|
||||||
@Override
|
|
||||||
protected void doInBackground()
|
|
||||||
{
|
|
||||||
view.refreshData();
|
|
||||||
}
|
|
||||||
}.execute();
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
waitForAsyncTasks();
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
throw new RuntimeException("Time out");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,93 @@
|
|||||||
|
/*
|
||||||
|
* 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.models.*;
|
||||||
|
import org.isoron.uhabits.utils.DateUtils;
|
||||||
|
|
||||||
|
public class HabitFixtures
|
||||||
|
{
|
||||||
|
public boolean NON_DAILY_HABIT_CHECKS[] = {
|
||||||
|
true, false, false, true, true, true, false, false, true, true
|
||||||
|
};
|
||||||
|
|
||||||
|
private ModelFactory modelFactory;
|
||||||
|
|
||||||
|
private final HabitList habitList;
|
||||||
|
|
||||||
|
public HabitFixtures(ModelFactory modelFactory, HabitList habitList)
|
||||||
|
{
|
||||||
|
this.modelFactory = modelFactory;
|
||||||
|
this.habitList = habitList;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Habit createEmptyHabit()
|
||||||
|
{
|
||||||
|
Habit habit = modelFactory.buildHabit();
|
||||||
|
habit.setName("Meditate");
|
||||||
|
habit.setDescription("Did you meditate this morning?");
|
||||||
|
habit.setColor(3);
|
||||||
|
habit.setFrequency(Frequency.DAILY);
|
||||||
|
habitList.add(habit);
|
||||||
|
return habit;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Habit createLongHabit()
|
||||||
|
{
|
||||||
|
Habit habit = createEmptyHabit();
|
||||||
|
habit.setFrequency(new Frequency(3, 7));
|
||||||
|
habit.setColor(4);
|
||||||
|
|
||||||
|
long day = DateUtils.millisecondsInOneDay;
|
||||||
|
long today = DateUtils.getStartOfToday();
|
||||||
|
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.getRepetitions().toggleTimestamp(today - mark * day);
|
||||||
|
|
||||||
|
return habit;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Habit createShortHabit()
|
||||||
|
{
|
||||||
|
Habit habit = modelFactory.buildHabit();
|
||||||
|
habit.setName("Wake up early");
|
||||||
|
habit.setDescription("Did you wake up before 6am?");
|
||||||
|
habit.setFrequency(new Frequency(2, 3));
|
||||||
|
habitList.add(habit);
|
||||||
|
|
||||||
|
long timestamp = DateUtils.getStartOfToday();
|
||||||
|
for (boolean c : NON_DAILY_HABIT_CHECKS)
|
||||||
|
{
|
||||||
|
if (c) habit.getRepetitions().toggleTimestamp(timestamp);
|
||||||
|
timestamp -= DateUtils.millisecondsInOneDay;
|
||||||
|
}
|
||||||
|
|
||||||
|
return habit;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void purgeHabits(HabitList habitList)
|
||||||
|
{
|
||||||
|
for (Habit h : habitList)
|
||||||
|
habitList.remove(h);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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;
|
||||||
|
|
||||||
|
import android.os.*;
|
||||||
|
import android.support.test.runner.*;
|
||||||
|
import android.test.suitebuilder.annotation.*;
|
||||||
|
|
||||||
|
import org.isoron.uhabits.models.*;
|
||||||
|
import org.isoron.uhabits.activities.*;
|
||||||
|
import org.junit.*;
|
||||||
|
import org.junit.runner.*;
|
||||||
|
|
||||||
|
import java.io.*;
|
||||||
|
|
||||||
|
import static org.hamcrest.MatcherAssert.*;
|
||||||
|
import static org.hamcrest.Matchers.*;
|
||||||
|
|
||||||
|
@RunWith(AndroidJUnit4.class)
|
||||||
|
@MediumTest
|
||||||
|
public class HabitLoggerTest extends BaseAndroidTest
|
||||||
|
{
|
||||||
|
@Test
|
||||||
|
public void testLogReminderScheduled() throws IOException
|
||||||
|
{
|
||||||
|
if (!isLogcatAvailable()) return;
|
||||||
|
|
||||||
|
long time = 1422277200000L; // 13:00 jan 26, 2015 (UTC)
|
||||||
|
Habit habit = fixtures.createEmptyHabit();
|
||||||
|
habit.setName("Write journal");
|
||||||
|
|
||||||
|
logger.logReminderScheduled(habit, time);
|
||||||
|
|
||||||
|
String expectedMsg = "Setting alarm (2015-01-26 130000): Wri\n";
|
||||||
|
assertLogcatContains(expectedMsg);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void assertLogcatContains(String expectedMsg) throws IOException
|
||||||
|
{
|
||||||
|
BaseSystem system = new BaseSystem(targetContext);
|
||||||
|
String logcat = system.getLogcat();
|
||||||
|
assertThat(logcat, containsString(expectedMsg));
|
||||||
|
}
|
||||||
|
|
||||||
|
protected boolean isLogcatAvailable()
|
||||||
|
{
|
||||||
|
return Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -17,24 +17,24 @@
|
|||||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.isoron.uhabits.unit;
|
package org.isoron.uhabits;
|
||||||
|
|
||||||
import android.os.Build;
|
import android.os.*;
|
||||||
import android.support.test.runner.AndroidJUnit4;
|
import android.support.test.runner.*;
|
||||||
import android.test.suitebuilder.annotation.SmallTest;
|
import android.test.suitebuilder.annotation.*;
|
||||||
|
|
||||||
import org.isoron.uhabits.HabitsApplication;
|
import org.isoron.uhabits.activities.*;
|
||||||
import org.junit.Test;
|
import org.junit.*;
|
||||||
import org.junit.runner.RunWith;
|
import org.junit.runner.*;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.*;
|
||||||
|
|
||||||
import static org.hamcrest.MatcherAssert.assertThat;
|
import static org.hamcrest.MatcherAssert.*;
|
||||||
import static org.hamcrest.Matchers.containsString;
|
import static org.hamcrest.Matchers.*;
|
||||||
|
|
||||||
@RunWith(AndroidJUnit4.class)
|
@RunWith(AndroidJUnit4.class)
|
||||||
@SmallTest
|
@MediumTest
|
||||||
public class HabitsApplicationTest
|
public class HabitsApplicationTest extends BaseAndroidTest
|
||||||
{
|
{
|
||||||
@Test
|
@Test
|
||||||
public void test_getLogcat() throws IOException
|
public void test_getLogcat() throws IOException
|
||||||
@@ -45,7 +45,8 @@ public class HabitsApplicationTest
|
|||||||
String msg = "LOGCAT TEST";
|
String msg = "LOGCAT TEST";
|
||||||
new RuntimeException(msg).printStackTrace();
|
new RuntimeException(msg).printStackTrace();
|
||||||
|
|
||||||
String log = HabitsApplication.getLogcat();
|
BaseSystem system = new BaseSystem(targetContext);
|
||||||
|
String log = system.getLogcat();
|
||||||
assertThat(log, containsString(msg));
|
assertThat(log, containsString(msg));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -17,56 +17,44 @@
|
|||||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.isoron.uhabits.unit.views;
|
package org.isoron.uhabits.activities.common.views;
|
||||||
|
|
||||||
import android.support.test.runner.AndroidJUnit4;
|
import android.support.test.runner.*;
|
||||||
import android.test.suitebuilder.annotation.SmallTest;
|
import android.test.suitebuilder.annotation.*;
|
||||||
|
|
||||||
import org.isoron.uhabits.models.Habit;
|
import org.isoron.uhabits.*;
|
||||||
import org.isoron.uhabits.unit.HabitFixtures;
|
import org.isoron.uhabits.models.*;
|
||||||
import org.isoron.uhabits.views.HabitFrequencyView;
|
import org.isoron.uhabits.utils.*;
|
||||||
import org.junit.Before;
|
import org.junit.*;
|
||||||
import org.junit.Test;
|
import org.junit.runner.*;
|
||||||
import org.junit.runner.RunWith;
|
|
||||||
|
|
||||||
@RunWith(AndroidJUnit4.class)
|
@RunWith(AndroidJUnit4.class)
|
||||||
@SmallTest
|
@MediumTest
|
||||||
public class HabitFrequencyViewTest extends ViewTest
|
public class FrequencyChartTest extends BaseViewTest
|
||||||
{
|
{
|
||||||
private HabitFrequencyView view;
|
public static final String BASE_PATH = "common/FrequencyChart/";
|
||||||
|
|
||||||
|
private FrequencyChart view;
|
||||||
|
|
||||||
|
@Override
|
||||||
@Before
|
@Before
|
||||||
public void setup()
|
public void setUp()
|
||||||
{
|
{
|
||||||
super.setup();
|
super.setUp();
|
||||||
|
|
||||||
HabitFixtures.purgeHabits();
|
fixtures.purgeHabits(habitList);
|
||||||
Habit habit = HabitFixtures.createLongHabit();
|
Habit habit = fixtures.createLongHabit();
|
||||||
|
|
||||||
view = new HabitFrequencyView(targetContext);
|
view = new FrequencyChart(targetContext);
|
||||||
view.setHabit(habit);
|
view.setFrequency(habit.getRepetitions().getWeekdayFrequency());
|
||||||
refreshData(view);
|
view.setColor(ColorUtils.getAndroidTestColor(habit.getColor()));
|
||||||
measureView(dpToPixels(300), dpToPixels(100), view);
|
measureView(view, dpToPixels(300), dpToPixels(100));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testRender() throws Throwable
|
public void testRender() throws Throwable
|
||||||
{
|
{
|
||||||
assertRenders(view, "HabitFrequencyView/render.png");
|
assertRenders(view, BASE_PATH + "render.png");
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testRender_withTransparentBackground() throws Throwable
|
|
||||||
{
|
|
||||||
view.setIsBackgroundTransparent(true);
|
|
||||||
assertRenders(view, "HabitFrequencyView/renderTransparent.png");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testRender_withDifferentSize() throws Throwable
|
|
||||||
{
|
|
||||||
measureView(dpToPixels(200), dpToPixels(200), view);
|
|
||||||
assertRenders(view, "HabitFrequencyView/renderDifferentSize.png");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -75,6 +63,20 @@ public class HabitFrequencyViewTest extends ViewTest
|
|||||||
view.onScroll(null, null, -dpToPixels(150), 0);
|
view.onScroll(null, null, -dpToPixels(150), 0);
|
||||||
view.invalidate();
|
view.invalidate();
|
||||||
|
|
||||||
assertRenders(view, "HabitFrequencyView/renderDataOffset.png");
|
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,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.common.views;
|
||||||
|
|
||||||
|
import android.support.test.runner.*;
|
||||||
|
import android.test.suitebuilder.annotation.*;
|
||||||
|
|
||||||
|
import org.isoron.uhabits.*;
|
||||||
|
import org.isoron.uhabits.models.*;
|
||||||
|
import org.isoron.uhabits.utils.*;
|
||||||
|
import org.junit.*;
|
||||||
|
import org.junit.runner.*;
|
||||||
|
|
||||||
|
@RunWith(AndroidJUnit4.class)
|
||||||
|
@MediumTest
|
||||||
|
public class HistoryChartTest extends BaseViewTest
|
||||||
|
{
|
||||||
|
private static final String BASE_PATH = "common/HistoryChart/";
|
||||||
|
|
||||||
|
private HistoryChart chart;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Before
|
||||||
|
public void setUp()
|
||||||
|
{
|
||||||
|
super.setUp();
|
||||||
|
|
||||||
|
fixtures.purgeHabits(habitList);
|
||||||
|
Habit habit = fixtures.createLongHabit();
|
||||||
|
|
||||||
|
chart = new HistoryChart(targetContext);
|
||||||
|
chart.setCheckmarks(habit.getCheckmarks().getAllValues());
|
||||||
|
chart.setColor(ColorUtils.getAndroidTestColor(habit.getColor()));
|
||||||
|
measureView(chart, dpToPixels(400), dpToPixels(200));
|
||||||
|
}
|
||||||
|
|
||||||
|
// @Test
|
||||||
|
// public void tapDate_atInvalidLocations() throws Throwable
|
||||||
|
// {
|
||||||
|
// int expectedCheckmarkValues[] = habit.getCheckmarks().getAllValues();
|
||||||
|
//
|
||||||
|
// chart.setIsEditable(true);
|
||||||
|
// tap(chart, 118, 13); // header
|
||||||
|
// tap(chart, 336, 60); // tomorrow's square
|
||||||
|
// tap(chart, 370, 60); // right axis
|
||||||
|
// waitForAsyncTasks();
|
||||||
|
//
|
||||||
|
// int actualCheckmarkValues[] = habit.getCheckmarks().getAllValues();
|
||||||
|
// assertThat(actualCheckmarkValues, equalTo(expectedCheckmarkValues));
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// @Test
|
||||||
|
// public void tapDate_withEditableView() throws Throwable
|
||||||
|
// {
|
||||||
|
// chart.setIsEditable(true);
|
||||||
|
// tap(chart, 340, 40); // today's square
|
||||||
|
// waitForAsyncTasks();
|
||||||
|
//
|
||||||
|
// long today = DateUtils.getStartOfToday();
|
||||||
|
// assertFalse(habit.getRepetitions().containsTimestamp(today));
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// @Test
|
||||||
|
// public void tapDate_withReadOnlyView() throws Throwable
|
||||||
|
// {
|
||||||
|
// chart.setIsEditable(false);
|
||||||
|
// tap(chart, 340, 40); // today's square
|
||||||
|
// waitForAsyncTasks();
|
||||||
|
//
|
||||||
|
// long today = DateUtils.getStartOfToday();
|
||||||
|
// assertTrue(habit.getRepetitions().containsTimestamp(today));
|
||||||
|
// }
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testRender() throws Throwable
|
||||||
|
{
|
||||||
|
assertRenders(chart, BASE_PATH + "render.png");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testRender_withDataOffset() throws Throwable
|
||||||
|
{
|
||||||
|
chart.onScroll(null, null, -dpToPixels(150), 0);
|
||||||
|
chart.invalidate();
|
||||||
|
|
||||||
|
assertRenders(chart, BASE_PATH + "renderDataOffset.png");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testRender_withDifferentSize() throws Throwable
|
||||||
|
{
|
||||||
|
measureView(chart, dpToPixels(200), dpToPixels(200));
|
||||||
|
assertRenders(chart, BASE_PATH + "renderDifferentSize.png");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testRender_withTransparentBackground() throws Throwable
|
||||||
|
{
|
||||||
|
chart.setIsBackgroundTransparent(true);
|
||||||
|
assertRenders(chart, BASE_PATH + "renderTransparent.png");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -17,35 +17,37 @@
|
|||||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.isoron.uhabits.unit.views;
|
package org.isoron.uhabits.activities.common.views;
|
||||||
|
|
||||||
import android.graphics.Color;
|
import android.graphics.*;
|
||||||
import android.support.test.runner.AndroidJUnit4;
|
import android.support.test.runner.*;
|
||||||
import android.test.suitebuilder.annotation.SmallTest;
|
import android.test.suitebuilder.annotation.*;
|
||||||
|
|
||||||
import org.isoron.uhabits.helpers.ColorHelper;
|
import org.isoron.uhabits.*;
|
||||||
import org.isoron.uhabits.views.RingView;
|
import org.isoron.uhabits.utils.*;
|
||||||
import org.junit.Before;
|
import org.junit.*;
|
||||||
import org.junit.Test;
|
import org.junit.runner.*;
|
||||||
import org.junit.runner.RunWith;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.*;
|
||||||
|
|
||||||
@RunWith(AndroidJUnit4.class)
|
@RunWith(AndroidJUnit4.class)
|
||||||
@SmallTest
|
@MediumTest
|
||||||
public class RingViewTest extends ViewTest
|
public class RingViewTest extends BaseViewTest
|
||||||
{
|
{
|
||||||
|
private static final String BASE_PATH = "common/RingView/";
|
||||||
|
|
||||||
private RingView view;
|
private RingView view;
|
||||||
|
|
||||||
|
@Override
|
||||||
@Before
|
@Before
|
||||||
public void setup()
|
public void setUp()
|
||||||
{
|
{
|
||||||
super.setup();
|
super.setUp();
|
||||||
|
|
||||||
view = new RingView(targetContext);
|
view = new RingView(targetContext);
|
||||||
view.setPercentage(0.6f);
|
view.setPercentage(0.6f);
|
||||||
view.setText("60%");
|
view.setText("60%");
|
||||||
view.setColor(ColorHelper.CSV_PALETTE[0]);
|
view.setColor(ColorUtils.getAndroidTestColor(0));
|
||||||
view.setBackgroundColor(Color.WHITE);
|
view.setBackgroundColor(Color.WHITE);
|
||||||
view.setThickness(dpToPixels(3));
|
view.setThickness(dpToPixels(3));
|
||||||
}
|
}
|
||||||
@@ -53,17 +55,17 @@ public class RingViewTest extends ViewTest
|
|||||||
@Test
|
@Test
|
||||||
public void testRender_base() throws IOException
|
public void testRender_base() throws IOException
|
||||||
{
|
{
|
||||||
measureView(dpToPixels(100), dpToPixels(100), view);
|
measureView(view, dpToPixels(100), dpToPixels(100));
|
||||||
assertRenders(view, "RingView/render.png");
|
assertRenders(view, BASE_PATH + "render.png");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testRender_withDifferentParams() throws IOException
|
public void testRender_withDifferentParams() throws IOException
|
||||||
{
|
{
|
||||||
view.setPercentage(0.25f);
|
view.setPercentage(0.25f);
|
||||||
view.setColor(ColorHelper.CSV_PALETTE[5]);
|
view.setColor(ColorUtils.getAndroidTestColor(5));
|
||||||
|
|
||||||
measureView(dpToPixels(200), dpToPixels(200), view);
|
measureView(view, dpToPixels(200), dpToPixels(200));
|
||||||
assertRenders(view, "RingView/renderDifferentParams.png");
|
assertRenders(view, BASE_PATH + "renderDifferentParams.png");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -17,60 +17,50 @@
|
|||||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.isoron.uhabits.unit.views;
|
package org.isoron.uhabits.activities.common.views;
|
||||||
|
|
||||||
import android.support.test.runner.AndroidJUnit4;
|
import android.support.test.runner.*;
|
||||||
import android.test.suitebuilder.annotation.SmallTest;
|
import android.test.suitebuilder.annotation.*;
|
||||||
import android.util.Log;
|
import android.util.*;
|
||||||
|
|
||||||
import org.isoron.uhabits.models.Habit;
|
import org.isoron.uhabits.*;
|
||||||
import org.isoron.uhabits.unit.HabitFixtures;
|
import org.isoron.uhabits.models.*;
|
||||||
import org.isoron.uhabits.views.HabitScoreView;
|
import org.isoron.uhabits.utils.*;
|
||||||
import org.junit.Before;
|
import org.junit.*;
|
||||||
import org.junit.Test;
|
import org.junit.runner.*;
|
||||||
import org.junit.runner.RunWith;
|
|
||||||
|
|
||||||
@RunWith(AndroidJUnit4.class)
|
@RunWith(AndroidJUnit4.class)
|
||||||
@SmallTest
|
@MediumTest
|
||||||
public class HabitScoreViewTest extends ViewTest
|
public class ScoreChartTest extends BaseViewTest
|
||||||
{
|
{
|
||||||
|
private static final String BASE_PATH = "common/ScoreChart/";
|
||||||
|
|
||||||
private Habit habit;
|
private Habit habit;
|
||||||
private HabitScoreView view;
|
|
||||||
|
|
||||||
|
private ScoreChart view;
|
||||||
|
|
||||||
|
@Override
|
||||||
@Before
|
@Before
|
||||||
public void setup()
|
public void setUp()
|
||||||
{
|
{
|
||||||
super.setup();
|
super.setUp();
|
||||||
|
|
||||||
HabitFixtures.purgeHabits();
|
fixtures.purgeHabits(habitList);
|
||||||
habit = HabitFixtures.createLongHabit();
|
habit = fixtures.createLongHabit();
|
||||||
|
|
||||||
view = new HabitScoreView(targetContext);
|
view = new ScoreChart(targetContext);
|
||||||
view.setHabit(habit);
|
view.setScores(habit.getScores().toList());
|
||||||
|
view.setColor(ColorUtils.getColor(targetContext, habit.getColor()));
|
||||||
view.setBucketSize(7);
|
view.setBucketSize(7);
|
||||||
refreshData(view);
|
measureView(view, dpToPixels(300), dpToPixels(200));
|
||||||
measureView(dpToPixels(300), dpToPixels(200), view);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testRender() throws Throwable
|
public void testRender() throws Throwable
|
||||||
{
|
{
|
||||||
Log.d("HabitScoreViewTest", String.format("height=%d", dpToPixels(100)));
|
Log.d("HabitScoreViewTest",
|
||||||
assertRenders(view, "HabitScoreView/render.png");
|
String.format("height=%d", dpToPixels(100)));
|
||||||
}
|
assertRenders(view, BASE_PATH + "render.png");
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testRender_withTransparentBackground() throws Throwable
|
|
||||||
{
|
|
||||||
view.setIsTransparencyEnabled(true);
|
|
||||||
assertRenders(view, "HabitScoreView/renderTransparent.png");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testRender_withDifferentSize() throws Throwable
|
|
||||||
{
|
|
||||||
measureView(dpToPixels(200), dpToPixels(200), view);
|
|
||||||
assertRenders(view, "HabitScoreView/renderDifferentSize.png");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -79,26 +69,40 @@ public class HabitScoreViewTest extends ViewTest
|
|||||||
view.onScroll(null, null, -dpToPixels(150), 0);
|
view.onScroll(null, null, -dpToPixels(150), 0);
|
||||||
view.invalidate();
|
view.invalidate();
|
||||||
|
|
||||||
assertRenders(view, "HabitScoreView/renderDataOffset.png");
|
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
|
@Test
|
||||||
public void testRender_withMonthlyBucket() throws Throwable
|
public void testRender_withMonthlyBucket() throws Throwable
|
||||||
{
|
{
|
||||||
|
view.setScores(habit.getScores().groupBy(DateUtils.TruncateField.MONTH));
|
||||||
view.setBucketSize(30);
|
view.setBucketSize(30);
|
||||||
view.refreshData();
|
|
||||||
view.invalidate();
|
view.invalidate();
|
||||||
|
|
||||||
assertRenders(view, "HabitScoreView/renderMonthly.png");
|
assertRenders(view, BASE_PATH + "renderMonthly.png");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testRender_withTransparentBackground() throws Throwable
|
||||||
|
{
|
||||||
|
view.setIsTransparencyEnabled(true);
|
||||||
|
assertRenders(view, BASE_PATH + "renderTransparent.png");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testRender_withYearlyBucket() throws Throwable
|
public void testRender_withYearlyBucket() throws Throwable
|
||||||
{
|
{
|
||||||
|
view.setScores(habit.getScores().groupBy(DateUtils.TruncateField.YEAR));
|
||||||
view.setBucketSize(365);
|
view.setBucketSize(365);
|
||||||
view.refreshData();
|
|
||||||
view.invalidate();
|
view.invalidate();
|
||||||
|
|
||||||
assertRenders(view, "HabitScoreView/renderYearly.png");
|
assertRenders(view, BASE_PATH + "renderYearly.png");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -17,58 +17,57 @@
|
|||||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.isoron.uhabits.unit.views;
|
package org.isoron.uhabits.activities.common.views;
|
||||||
|
|
||||||
import android.support.test.runner.AndroidJUnit4;
|
import android.support.test.runner.*;
|
||||||
import android.test.suitebuilder.annotation.SmallTest;
|
import android.test.suitebuilder.annotation.*;
|
||||||
|
|
||||||
import org.isoron.uhabits.models.Habit;
|
import org.isoron.uhabits.*;
|
||||||
import org.isoron.uhabits.unit.HabitFixtures;
|
import org.isoron.uhabits.models.*;
|
||||||
import org.isoron.uhabits.views.HabitStreakView;
|
import org.isoron.uhabits.utils.*;
|
||||||
import org.junit.Before;
|
import org.junit.*;
|
||||||
import org.junit.Test;
|
import org.junit.runner.*;
|
||||||
import org.junit.runner.RunWith;
|
|
||||||
|
|
||||||
@RunWith(AndroidJUnit4.class)
|
@RunWith(AndroidJUnit4.class)
|
||||||
@SmallTest
|
@MediumTest
|
||||||
public class HabitStreakViewTest extends ViewTest
|
public class StreakChartTest extends BaseViewTest
|
||||||
{
|
{
|
||||||
private HabitStreakView view;
|
private static final String BASE_PATH = "common/StreakChart/";
|
||||||
|
|
||||||
|
private StreakChart view;
|
||||||
|
|
||||||
|
@Override
|
||||||
@Before
|
@Before
|
||||||
public void setup()
|
public void setUp()
|
||||||
{
|
{
|
||||||
super.setup();
|
super.setUp();
|
||||||
|
|
||||||
HabitFixtures.purgeHabits();
|
fixtures.purgeHabits(habitList);
|
||||||
Habit habit = HabitFixtures.createLongHabit();
|
Habit habit = fixtures.createLongHabit();
|
||||||
|
|
||||||
view = new HabitStreakView(targetContext);
|
view = new StreakChart(targetContext);
|
||||||
measureView(dpToPixels(300), dpToPixels(100), view);
|
view.setColor(ColorUtils.getAndroidTestColor(habit.getColor()));
|
||||||
|
view.setStreaks(habit.getStreaks().getBest(5));
|
||||||
view.setHabit(habit);
|
measureView(view, dpToPixels(300), dpToPixels(100));
|
||||||
refreshData(view);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testRender() throws Throwable
|
public void testRender() throws Throwable
|
||||||
{
|
{
|
||||||
assertRenders(view, "HabitStreakView/render.png");
|
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
|
@Test
|
||||||
public void testRender_withTransparentBackground() throws Throwable
|
public void testRender_withTransparentBackground() throws Throwable
|
||||||
{
|
{
|
||||||
view.setIsBackgroundTransparent(true);
|
view.setIsBackgroundTransparent(true);
|
||||||
assertRenders(view, "HabitStreakView/renderTransparent.png");
|
assertRenders(view, BASE_PATH + "renderTransparent.png");
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testRender_withSmallSize() throws Throwable
|
|
||||||
{
|
|
||||||
measureView(dpToPixels(100), dpToPixels(100), view);
|
|
||||||
refreshData(view);
|
|
||||||
|
|
||||||
assertRenders(view, "HabitStreakView/renderSmallSize.png");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,187 @@
|
|||||||
|
/*
|
||||||
|
* 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 android.support.test.runner.*;
|
||||||
|
import android.test.suitebuilder.annotation.*;
|
||||||
|
|
||||||
|
import org.isoron.uhabits.*;
|
||||||
|
import org.isoron.uhabits.models.*;
|
||||||
|
import org.isoron.uhabits.utils.*;
|
||||||
|
import org.junit.*;
|
||||||
|
import org.junit.runner.*;
|
||||||
|
|
||||||
|
import java.io.*;
|
||||||
|
import java.util.concurrent.*;
|
||||||
|
|
||||||
|
@RunWith(AndroidJUnit4.class)
|
||||||
|
@MediumTest
|
||||||
|
public class CheckmarkButtonViewTest extends BaseViewTest
|
||||||
|
{
|
||||||
|
public static final String PATH = "habits/list/CheckmarkButtonView/";
|
||||||
|
|
||||||
|
private CountDownLatch latch;
|
||||||
|
|
||||||
|
private CheckmarkButtonView view;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Before
|
||||||
|
public void setUp()
|
||||||
|
{
|
||||||
|
super.setUp();
|
||||||
|
setSimilarityCutoff(0.03f);
|
||||||
|
|
||||||
|
latch = new CountDownLatch(1);
|
||||||
|
view = new CheckmarkButtonView(targetContext);
|
||||||
|
view.setValue(Checkmark.UNCHECKED);
|
||||||
|
view.setColor(ColorUtils.getAndroidTestColor(7));
|
||||||
|
|
||||||
|
measureView(view, dpToPixels(40), dpToPixels(40));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testRender_explicitCheck() throws Exception
|
||||||
|
{
|
||||||
|
view.setValue(Checkmark.CHECKED_EXPLICITLY);
|
||||||
|
assertRendersCheckedExplicitly();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testRender_implicitCheck() throws Exception
|
||||||
|
{
|
||||||
|
view.setValue(Checkmark.CHECKED_IMPLICITLY);
|
||||||
|
assertRendersCheckedImplicitly();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testRender_unchecked() throws Exception
|
||||||
|
{
|
||||||
|
view.setValue(Checkmark.UNCHECKED);
|
||||||
|
assertRendersUnchecked();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void assertRendersCheckedExplicitly() throws IOException
|
||||||
|
{
|
||||||
|
assertRenders(view, PATH + "render_explicit_check.png");
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void assertRendersCheckedImplicitly() throws IOException
|
||||||
|
{
|
||||||
|
assertRenders(view, PATH + "render_implicit_check.png");
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void assertRendersUnchecked() throws IOException
|
||||||
|
{
|
||||||
|
assertRenders(view, PATH + "render_unchecked.png");
|
||||||
|
}
|
||||||
|
|
||||||
|
// @Test
|
||||||
|
// public void testLongClick() throws Exception
|
||||||
|
// {
|
||||||
|
// setOnToggleListener();
|
||||||
|
// view.performLongClick();
|
||||||
|
// waitForLatch();
|
||||||
|
// assertRendersCheckedExplicitly();
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// @Test
|
||||||
|
// public void testClick_withShortToggle_fromUnchecked() throws Exception
|
||||||
|
// {
|
||||||
|
// Preferences.getInstance().setShortToggleEnabled(true);
|
||||||
|
// view.setValue(Checkmark.UNCHECKED);
|
||||||
|
// setOnToggleListenerAndPerformClick();
|
||||||
|
// assertRendersCheckedExplicitly();
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// @Test
|
||||||
|
// public void testClick_withShortToggle_fromChecked() throws Exception
|
||||||
|
// {
|
||||||
|
// Preferences.getInstance().setShortToggleEnabled(true);
|
||||||
|
// view.setValue(Checkmark.CHECKED_EXPLICITLY);
|
||||||
|
// setOnToggleListenerAndPerformClick();
|
||||||
|
// assertRendersUnchecked();
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// @Test
|
||||||
|
// public void testClick_withShortToggle_withoutListener() throws Exception
|
||||||
|
// {
|
||||||
|
// Preferences.getInstance().setShortToggleEnabled(true);
|
||||||
|
// view.setValue(Checkmark.CHECKED_EXPLICITLY);
|
||||||
|
// view.setController(null);
|
||||||
|
// view.performClick();
|
||||||
|
// assertRendersUnchecked();
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// protected void setOnToggleListenerAndPerformClick() throws InterruptedException
|
||||||
|
// {
|
||||||
|
// setOnToggleListener();
|
||||||
|
// view.performClick();
|
||||||
|
// waitForLatch();
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// @Test
|
||||||
|
// public void testClick_withoutShortToggle() throws Exception
|
||||||
|
// {
|
||||||
|
// Preferences.getInstance().setShortToggleEnabled(false);
|
||||||
|
// setOnInvalidToggleListener();
|
||||||
|
// view.performClick();
|
||||||
|
// waitForLatch();
|
||||||
|
// assertRendersUnchecked();
|
||||||
|
// }
|
||||||
|
|
||||||
|
// protected void setOnInvalidToggleListener()
|
||||||
|
// {
|
||||||
|
// view.setController(new CheckmarkButtonView.Controller()
|
||||||
|
// {
|
||||||
|
// @Override
|
||||||
|
// public void onToggleCheckmark(CheckmarkButtonView view, long timestamp)
|
||||||
|
// {
|
||||||
|
// fail();
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// @Override
|
||||||
|
// public void onInvalidToggle(CheckmarkButtonView v)
|
||||||
|
// {
|
||||||
|
// assertThat(v, equalTo(view));
|
||||||
|
// latch.countDown();
|
||||||
|
// }
|
||||||
|
// });
|
||||||
|
// }
|
||||||
|
|
||||||
|
// protected void setOnToggleListener()
|
||||||
|
// {
|
||||||
|
// view.setController(new CheckmarkButtonView.Controller()
|
||||||
|
// {
|
||||||
|
// @Override
|
||||||
|
// public void onToggleCheckmark(CheckmarkButtonView v, long t)
|
||||||
|
// {
|
||||||
|
// assertThat(v, equalTo(view));
|
||||||
|
// assertThat(t, equalTo(DateUtils.getStartOfToday()));
|
||||||
|
// latch.countDown();
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// @Override
|
||||||
|
// public void onInvalidToggle(CheckmarkButtonView view)
|
||||||
|
// {
|
||||||
|
// fail();
|
||||||
|
// }
|
||||||
|
// });
|
||||||
|
// }
|
||||||
|
}
|
||||||
@@ -0,0 +1,97 @@
|
|||||||
|
/*
|
||||||
|
* 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 android.support.test.runner.AndroidJUnit4;
|
||||||
|
import android.test.suitebuilder.annotation.*;
|
||||||
|
|
||||||
|
import org.isoron.uhabits.models.Checkmark;
|
||||||
|
import org.isoron.uhabits.models.Habit;
|
||||||
|
import org.isoron.uhabits.BaseViewTest;
|
||||||
|
import org.isoron.uhabits.utils.ColorUtils;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
|
||||||
|
import java.util.concurrent.CountDownLatch;
|
||||||
|
|
||||||
|
@RunWith(AndroidJUnit4.class)
|
||||||
|
@MediumTest
|
||||||
|
public class CheckmarkPanelViewTest extends BaseViewTest
|
||||||
|
{
|
||||||
|
public static final String PATH = "habits/list/CheckmarkPanelView/";
|
||||||
|
|
||||||
|
private CountDownLatch latch;
|
||||||
|
private CheckmarkPanelView view;
|
||||||
|
private int checkmarks[];
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Before
|
||||||
|
public void setUp()
|
||||||
|
{
|
||||||
|
super.setUp();
|
||||||
|
setSimilarityCutoff(0.03f);
|
||||||
|
prefs.setShouldReverseCheckmarks(false);
|
||||||
|
|
||||||
|
Habit habit = fixtures.createEmptyHabit();
|
||||||
|
|
||||||
|
latch = new CountDownLatch(1);
|
||||||
|
checkmarks = new int[]{
|
||||||
|
Checkmark.CHECKED_EXPLICITLY, Checkmark.UNCHECKED,
|
||||||
|
Checkmark.CHECKED_IMPLICITLY, Checkmark.CHECKED_EXPLICITLY};
|
||||||
|
|
||||||
|
view = new CheckmarkPanelView(targetContext);
|
||||||
|
view.setHabit(habit);
|
||||||
|
view.setCheckmarkValues(checkmarks);
|
||||||
|
view.setColor(ColorUtils.getAndroidTestColor(7));
|
||||||
|
|
||||||
|
measureView(view, dpToPixels(200), dpToPixels(200));
|
||||||
|
}
|
||||||
|
|
||||||
|
// protected void waitForLatch() throws InterruptedException
|
||||||
|
// {
|
||||||
|
// assertTrue("Latch timeout", latch.await(1, TimeUnit.SECONDS));
|
||||||
|
// }
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testRender() throws Exception
|
||||||
|
{
|
||||||
|
assertRenders(view, PATH + "render.png");
|
||||||
|
}
|
||||||
|
|
||||||
|
// @Test
|
||||||
|
// public void testToggleCheckmark_withLeftToRight() throws Exception
|
||||||
|
// {
|
||||||
|
// setToggleListener();
|
||||||
|
// view.getButton(1).performToggle();
|
||||||
|
// waitForLatch();
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// @Test
|
||||||
|
// public void testToggleCheckmark_withReverseCheckmarks() throws Exception
|
||||||
|
// {
|
||||||
|
// prefs.setShouldReverseCheckmarks(true);
|
||||||
|
// view.setCheckmarkValues(checkmarks); // refresh after preference change
|
||||||
|
//
|
||||||
|
// setToggleListener();
|
||||||
|
// view.getButton(2).performToggle();
|
||||||
|
// waitForLatch();
|
||||||
|
// }
|
||||||
|
}
|
||||||
@@ -0,0 +1,91 @@
|
|||||||
|
/*
|
||||||
|
* 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 android.support.test.runner.*;
|
||||||
|
import android.test.suitebuilder.annotation.*;
|
||||||
|
|
||||||
|
import org.isoron.uhabits.*;
|
||||||
|
import org.isoron.uhabits.models.*;
|
||||||
|
import org.isoron.uhabits.utils.*;
|
||||||
|
import org.junit.*;
|
||||||
|
import org.junit.runner.*;
|
||||||
|
|
||||||
|
import static org.mockito.Mockito.mock;
|
||||||
|
|
||||||
|
@RunWith(AndroidJUnit4.class)
|
||||||
|
@MediumTest
|
||||||
|
public class HabitCardViewTest extends BaseViewTest
|
||||||
|
{
|
||||||
|
private HabitCardView view;
|
||||||
|
|
||||||
|
public static final String PATH = "habits/list/HabitCardView/";
|
||||||
|
|
||||||
|
private HabitCardView.Controller controller;
|
||||||
|
|
||||||
|
private Habit habit;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setUp()
|
||||||
|
{
|
||||||
|
super.setUp();
|
||||||
|
setTheme(R.style.AppBaseTheme);
|
||||||
|
|
||||||
|
habit = fixtures.createLongHabit();
|
||||||
|
CheckmarkList checkmarks = habit.getCheckmarks();
|
||||||
|
|
||||||
|
long today = DateUtils.getStartOfToday();
|
||||||
|
long day = DateUtils.millisecondsInOneDay;
|
||||||
|
int[] values = checkmarks.getValues(today - 5 * day, today);
|
||||||
|
|
||||||
|
controller = mock(HabitCardView.Controller.class);
|
||||||
|
|
||||||
|
view = new HabitCardView(targetContext);
|
||||||
|
view.setHabit(habit);
|
||||||
|
view.setCheckmarkValues(values);
|
||||||
|
view.setSelected(false);
|
||||||
|
view.setScore(habit.getScores().getTodayValue());
|
||||||
|
view.setController(controller);
|
||||||
|
measureView(view, dpToPixels(400), dpToPixels(50));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testRender() throws Exception
|
||||||
|
{
|
||||||
|
assertRenders(view, PATH + "render.png");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testRender_selected() throws Exception
|
||||||
|
{
|
||||||
|
view.setSelected(true);
|
||||||
|
measureView(view, dpToPixels(400), dpToPixels(50));
|
||||||
|
assertRenders(view, PATH + "render_selected.png");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testChangeModel() throws Exception
|
||||||
|
{
|
||||||
|
habit.setName("Wake up early");
|
||||||
|
habit.setColor(2);
|
||||||
|
habit.getObservable().notifyListeners();
|
||||||
|
assertRenders(view, PATH + "render_changed.png");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,79 @@
|
|||||||
|
/*
|
||||||
|
* 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 android.support.test.runner.*;
|
||||||
|
import android.test.suitebuilder.annotation.*;
|
||||||
|
|
||||||
|
import org.isoron.uhabits.*;
|
||||||
|
import org.isoron.uhabits.activities.habits.list.model.*;
|
||||||
|
import org.junit.*;
|
||||||
|
import org.junit.runner.*;
|
||||||
|
|
||||||
|
import static org.hamcrest.MatcherAssert.*;
|
||||||
|
import static org.hamcrest.Matchers.*;
|
||||||
|
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();
|
||||||
|
|
||||||
|
view = new HintView(targetContext);
|
||||||
|
list = mock(HintList.class);
|
||||||
|
view.setHints(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,64 @@
|
|||||||
|
/*
|
||||||
|
* 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.support.test.runner.*;
|
||||||
|
import android.test.suitebuilder.annotation.*;
|
||||||
|
import android.view.*;
|
||||||
|
|
||||||
|
import org.isoron.uhabits.*;
|
||||||
|
import org.isoron.uhabits.models.*;
|
||||||
|
import org.junit.*;
|
||||||
|
import org.junit.runner.*;
|
||||||
|
|
||||||
|
@RunWith(AndroidJUnit4.class)
|
||||||
|
@MediumTest
|
||||||
|
public class FrequencyCardTest extends BaseViewTest
|
||||||
|
{
|
||||||
|
public static final String PATH = "habits/show/FrequencyCard/";
|
||||||
|
|
||||||
|
private FrequencyCard view;
|
||||||
|
|
||||||
|
private Habit habit;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
@Override
|
||||||
|
public void setUp()
|
||||||
|
{
|
||||||
|
super.setUp();
|
||||||
|
habit = fixtures.createLongHabit();
|
||||||
|
|
||||||
|
view = (FrequencyCard) LayoutInflater
|
||||||
|
.from(targetContext)
|
||||||
|
.inflate(R.layout.show_habit, null)
|
||||||
|
.findViewById(R.id.frequencyCard);
|
||||||
|
|
||||||
|
view.setHabit(habit);
|
||||||
|
view.refreshData();
|
||||||
|
|
||||||
|
measureView(view, 800, 600);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testRender() throws Exception
|
||||||
|
{
|
||||||
|
assertRenders(view, PATH + "render.png");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,64 @@
|
|||||||
|
/*
|
||||||
|
* 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.support.test.runner.*;
|
||||||
|
import android.test.suitebuilder.annotation.*;
|
||||||
|
import android.view.*;
|
||||||
|
|
||||||
|
import org.isoron.uhabits.*;
|
||||||
|
import org.isoron.uhabits.models.*;
|
||||||
|
import org.junit.*;
|
||||||
|
import org.junit.runner.*;
|
||||||
|
|
||||||
|
@RunWith(AndroidJUnit4.class)
|
||||||
|
@MediumTest
|
||||||
|
public class HistoryCardTest extends BaseViewTest
|
||||||
|
{
|
||||||
|
public static final String PATH = "habits/show/HistoryCard/";
|
||||||
|
|
||||||
|
private HistoryCard view;
|
||||||
|
|
||||||
|
private Habit habit;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
@Override
|
||||||
|
public void setUp()
|
||||||
|
{
|
||||||
|
super.setUp();
|
||||||
|
habit = fixtures.createLongHabit();
|
||||||
|
|
||||||
|
view = (HistoryCard) LayoutInflater
|
||||||
|
.from(targetContext)
|
||||||
|
.inflate(R.layout.show_habit, null)
|
||||||
|
.findViewById(R.id.historyCard);
|
||||||
|
|
||||||
|
view.setHabit(habit);
|
||||||
|
view.refreshData();
|
||||||
|
|
||||||
|
measureView(view, 800, 600);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testRender() throws Exception
|
||||||
|
{
|
||||||
|
assertRenders(view, PATH + "render.png");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,63 @@
|
|||||||
|
/*
|
||||||
|
* 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.support.test.runner.*;
|
||||||
|
import android.test.suitebuilder.annotation.*;
|
||||||
|
import android.view.*;
|
||||||
|
|
||||||
|
import org.isoron.uhabits.*;
|
||||||
|
import org.isoron.uhabits.models.*;
|
||||||
|
import org.junit.*;
|
||||||
|
import org.junit.runner.*;
|
||||||
|
|
||||||
|
@RunWith(AndroidJUnit4.class)
|
||||||
|
@MediumTest
|
||||||
|
public class OverviewCardTest extends BaseViewTest
|
||||||
|
{
|
||||||
|
public static final String PATH = "habits/show/OverviewCard/";
|
||||||
|
|
||||||
|
private OverviewCard view;
|
||||||
|
|
||||||
|
private Habit habit;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
@Override
|
||||||
|
public void setUp()
|
||||||
|
{
|
||||||
|
super.setUp();
|
||||||
|
habit = fixtures.createLongHabit();
|
||||||
|
|
||||||
|
view = (OverviewCard) LayoutInflater
|
||||||
|
.from(targetContext)
|
||||||
|
.inflate(R.layout.show_habit, null)
|
||||||
|
.findViewById(R.id.overviewCard);
|
||||||
|
|
||||||
|
view.setHabit(habit);
|
||||||
|
view.refreshData();
|
||||||
|
measureView(view, 800, 300);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testRender() throws Exception
|
||||||
|
{
|
||||||
|
assertRenders(view, PATH + "render.png");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,63 @@
|
|||||||
|
/*
|
||||||
|
* 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.support.test.runner.*;
|
||||||
|
import android.test.suitebuilder.annotation.*;
|
||||||
|
import android.view.*;
|
||||||
|
|
||||||
|
import org.isoron.uhabits.*;
|
||||||
|
import org.isoron.uhabits.models.*;
|
||||||
|
import org.junit.*;
|
||||||
|
import org.junit.runner.*;
|
||||||
|
|
||||||
|
@RunWith(AndroidJUnit4.class)
|
||||||
|
@MediumTest
|
||||||
|
public class ScoreCardTest extends BaseViewTest
|
||||||
|
{
|
||||||
|
public static final String PATH = "habits/show/ScoreCard/";
|
||||||
|
|
||||||
|
private ScoreCard view;
|
||||||
|
|
||||||
|
private Habit habit;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
@Override
|
||||||
|
public void setUp()
|
||||||
|
{
|
||||||
|
super.setUp();
|
||||||
|
habit = fixtures.createLongHabit();
|
||||||
|
|
||||||
|
view = (ScoreCard) LayoutInflater
|
||||||
|
.from(targetContext)
|
||||||
|
.inflate(R.layout.show_habit, null)
|
||||||
|
.findViewById(R.id.scoreCard);
|
||||||
|
|
||||||
|
view.setHabit(habit);
|
||||||
|
view.refreshData();
|
||||||
|
measureView(view, 800, 600);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testRender() throws Exception
|
||||||
|
{
|
||||||
|
assertRenders(view, PATH + "render.png");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,64 @@
|
|||||||
|
/*
|
||||||
|
* 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.support.test.runner.*;
|
||||||
|
import android.test.suitebuilder.annotation.*;
|
||||||
|
import android.view.*;
|
||||||
|
|
||||||
|
import org.isoron.uhabits.*;
|
||||||
|
import org.isoron.uhabits.models.*;
|
||||||
|
import org.junit.*;
|
||||||
|
import org.junit.runner.*;
|
||||||
|
|
||||||
|
@RunWith(AndroidJUnit4.class)
|
||||||
|
@MediumTest
|
||||||
|
public class StreakCardTest extends BaseViewTest
|
||||||
|
{
|
||||||
|
public static final String PATH = "habits/show/StreakCard/";
|
||||||
|
|
||||||
|
private StreakCard view;
|
||||||
|
|
||||||
|
private Habit habit;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
@Override
|
||||||
|
public void setUp()
|
||||||
|
{
|
||||||
|
super.setUp();
|
||||||
|
habit = fixtures.createLongHabit();
|
||||||
|
|
||||||
|
view = (StreakCard) LayoutInflater
|
||||||
|
.from(targetContext)
|
||||||
|
.inflate(R.layout.show_habit, null)
|
||||||
|
.findViewById(R.id.streakCard);
|
||||||
|
|
||||||
|
view.setHabit(habit);
|
||||||
|
view.refreshData();
|
||||||
|
|
||||||
|
measureView(view, 800, 600);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testRender() throws Exception
|
||||||
|
{
|
||||||
|
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.support.test.runner.*;
|
||||||
|
import android.test.suitebuilder.annotation.*;
|
||||||
|
import android.view.*;
|
||||||
|
|
||||||
|
import org.isoron.uhabits.*;
|
||||||
|
import org.isoron.uhabits.models.*;
|
||||||
|
import org.junit.*;
|
||||||
|
import org.junit.runner.*;
|
||||||
|
|
||||||
|
@RunWith(AndroidJUnit4.class)
|
||||||
|
@MediumTest
|
||||||
|
public class SubtitleCardTest extends BaseViewTest
|
||||||
|
{
|
||||||
|
public static final String PATH = "habits/show/SubtitleCard/";
|
||||||
|
|
||||||
|
private SubtitleCard view;
|
||||||
|
|
||||||
|
private Habit habit;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
@Override
|
||||||
|
public void setUp()
|
||||||
|
{
|
||||||
|
super.setUp();
|
||||||
|
|
||||||
|
habit = fixtures.createLongHabit();
|
||||||
|
habit.setReminder(new Reminder(8, 30, WeekdayList.EVERY_DAY));
|
||||||
|
|
||||||
|
view = (SubtitleCard) LayoutInflater
|
||||||
|
.from(targetContext)
|
||||||
|
.inflate(R.layout.show_habit, null)
|
||||||
|
.findViewById(R.id.subtitleCard);
|
||||||
|
|
||||||
|
view.setHabit(habit);
|
||||||
|
view.refreshData();
|
||||||
|
|
||||||
|
measureView(view, 800, 200);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testRender() throws Exception
|
||||||
|
{
|
||||||
|
assertRenders(view, PATH + "render.png");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -17,7 +17,7 @@
|
|||||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.isoron.uhabits.ui;
|
package org.isoron.uhabits.espresso;
|
||||||
|
|
||||||
import android.preference.Preference;
|
import android.preference.Preference;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
@@ -39,7 +39,7 @@ public class HabitMatchers
|
|||||||
@Override
|
@Override
|
||||||
public boolean matchesSafely(Habit habit)
|
public boolean matchesSafely(Habit habit)
|
||||||
{
|
{
|
||||||
return habit.name.equals(name);
|
return habit.getName().equals(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -51,7 +51,7 @@ public class HabitMatchers
|
|||||||
@Override
|
@Override
|
||||||
public void describeMismatchSafely(Habit habit, Description description)
|
public void describeMismatchSafely(Habit habit, Description description)
|
||||||
{
|
{
|
||||||
description.appendText("was ").appendText(habit.name);
|
description.appendText("was ").appendText(habit.getName());
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -17,7 +17,7 @@
|
|||||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.isoron.uhabits.ui;
|
package org.isoron.uhabits.espresso;
|
||||||
|
|
||||||
import android.support.test.espresso.UiController;
|
import android.support.test.espresso.UiController;
|
||||||
import android.support.test.espresso.ViewAction;
|
import android.support.test.espresso.ViewAction;
|
||||||
@@ -61,7 +61,7 @@ public class HabitViewActions
|
|||||||
@Override
|
@Override
|
||||||
public void perform(UiController uiController, View view)
|
public void perform(UiController uiController, View view)
|
||||||
{
|
{
|
||||||
if (view.getId() != R.id.llButtons)
|
if (view.getId() != R.id.checkmarkPanel)
|
||||||
throw new InvalidParameterException("View must have id llButtons");
|
throw new InvalidParameterException("View must have id llButtons");
|
||||||
|
|
||||||
LinearLayout llButtons = (LinearLayout) view;
|
LinearLayout llButtons = (LinearLayout) view;
|
||||||
@@ -0,0 +1,199 @@
|
|||||||
|
/*
|
||||||
|
* 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.espresso;
|
||||||
|
|
||||||
|
import android.support.test.espresso.*;
|
||||||
|
import android.support.test.espresso.contrib.*;
|
||||||
|
|
||||||
|
import org.hamcrest.*;
|
||||||
|
import org.isoron.uhabits.R;
|
||||||
|
import org.isoron.uhabits.models.*;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
import static android.support.test.espresso.Espresso.*;
|
||||||
|
import static android.support.test.espresso.Espresso.pressBack;
|
||||||
|
import static android.support.test.espresso.action.ViewActions.*;
|
||||||
|
import static android.support.test.espresso.assertion.ViewAssertions.*;
|
||||||
|
import static android.support.test.espresso.matcher.RootMatchers.*;
|
||||||
|
import static android.support.test.espresso.matcher.ViewMatchers.Visibility.*;
|
||||||
|
import static android.support.test.espresso.matcher.ViewMatchers.*;
|
||||||
|
import static org.hamcrest.Matchers.*;
|
||||||
|
|
||||||
|
public class MainActivityActions
|
||||||
|
{
|
||||||
|
public static String addHabit()
|
||||||
|
{
|
||||||
|
return addHabit(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String addHabit(boolean openDialogs)
|
||||||
|
{
|
||||||
|
String name = "New Habit " + new Random().nextInt(1000000);
|
||||||
|
String description = "Did you perform your new habit today?";
|
||||||
|
String num = "4";
|
||||||
|
String den = "8";
|
||||||
|
|
||||||
|
onView(withId(R.id.actionAdd)).perform(click());
|
||||||
|
|
||||||
|
typeHabitData(name, description, num, den);
|
||||||
|
|
||||||
|
if (openDialogs)
|
||||||
|
{
|
||||||
|
onView(withId(R.id.buttonPickColor)).perform(click());
|
||||||
|
pressBack();
|
||||||
|
onView(withId(R.id.tvReminderTime)).perform(click());
|
||||||
|
onView(withText("Done")).perform(click());
|
||||||
|
onView(withId(R.id.tvReminderDays)).perform(click());
|
||||||
|
onView(withText("OK")).perform(click());
|
||||||
|
}
|
||||||
|
|
||||||
|
onView(withId(R.id.buttonSave)).perform(click());
|
||||||
|
|
||||||
|
onData(Matchers.allOf(is(instanceOf(Habit.class)),
|
||||||
|
HabitMatchers.withName(name))).onChildView(withId(R.id.label));
|
||||||
|
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void assertHabitExists(String name)
|
||||||
|
{
|
||||||
|
List<String> names = new LinkedList<>();
|
||||||
|
names.add(name);
|
||||||
|
assertHabitsExist(names);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void assertHabitsDontExist(List<String> names)
|
||||||
|
{
|
||||||
|
for (String name : names)
|
||||||
|
onView(withId(R.id.listView)).check(matches(Matchers.not(
|
||||||
|
HabitMatchers.containsHabit(HabitMatchers.withName(name)))));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void assertHabitsExist(List<String> names)
|
||||||
|
{
|
||||||
|
for (String name : names)
|
||||||
|
onData(Matchers.allOf(is(instanceOf(Habit.class)),
|
||||||
|
HabitMatchers.withName(name))).check(matches(isDisplayed()));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void clickHiddenMenuItem(int stringId)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// Try the ActionMode overflow menu first
|
||||||
|
onView(allOf(withContentDescription("More options"), withParent(
|
||||||
|
withParent(withClassName(containsString("Action")))))).perform(
|
||||||
|
click());
|
||||||
|
}
|
||||||
|
catch (Exception e1)
|
||||||
|
{
|
||||||
|
// Try the toolbar overflow menu
|
||||||
|
onView(allOf(withContentDescription("More options"), withParent(
|
||||||
|
withParent(withClassName(containsString("Toolbar")))))).perform(
|
||||||
|
click());
|
||||||
|
}
|
||||||
|
|
||||||
|
onView(withText(stringId)).perform(click());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void clickMenuItem(int stringId)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
onView(withText(stringId)).perform(click());
|
||||||
|
}
|
||||||
|
catch (Exception e1)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
onView(withContentDescription(stringId)).perform(click());
|
||||||
|
}
|
||||||
|
catch (Exception e2)
|
||||||
|
{
|
||||||
|
clickHiddenMenuItem(stringId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void clickSettingsItem(String text)
|
||||||
|
{
|
||||||
|
onView(withClassName(containsString("RecyclerView"))).perform(
|
||||||
|
RecyclerViewActions.actionOnItem(
|
||||||
|
hasDescendant(withText(containsString(text))), click()));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void deleteHabit(String name)
|
||||||
|
{
|
||||||
|
deleteHabits(Collections.singletonList(name));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void deleteHabits(List<String> names)
|
||||||
|
{
|
||||||
|
selectHabits(names);
|
||||||
|
clickMenuItem(R.string.delete);
|
||||||
|
onView(withText("OK")).perform(click());
|
||||||
|
assertHabitsDontExist(names);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void selectHabit(String name)
|
||||||
|
{
|
||||||
|
selectHabits(Collections.singletonList(name));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void selectHabits(List<String> names)
|
||||||
|
{
|
||||||
|
boolean first = true;
|
||||||
|
for (String name : names)
|
||||||
|
{
|
||||||
|
onData(Matchers.allOf(is(instanceOf(Habit.class)),
|
||||||
|
HabitMatchers.withName(name)))
|
||||||
|
.onChildView(withId(R.id.label))
|
||||||
|
.perform(first ? longClick() : click());
|
||||||
|
|
||||||
|
first = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void typeHabitData(String name,
|
||||||
|
String description,
|
||||||
|
String num,
|
||||||
|
String den)
|
||||||
|
{
|
||||||
|
onView(withId(R.id.tvName)).perform(replaceText(name));
|
||||||
|
onView(withId(R.id.tvDescription)).perform(replaceText(description));
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
onView(allOf(withId(R.id.sFrequency),
|
||||||
|
withEffectiveVisibility(VISIBLE))).perform(click());
|
||||||
|
onData(allOf(instanceOf(String.class), startsWith("Custom")))
|
||||||
|
.inRoot(isPlatformPopup())
|
||||||
|
.perform(click());
|
||||||
|
}
|
||||||
|
catch (NoMatchingViewException e)
|
||||||
|
{
|
||||||
|
// ignored
|
||||||
|
}
|
||||||
|
|
||||||
|
onView(withId(R.id.tvFreqNum)).perform(replaceText(num));
|
||||||
|
onView(withId(R.id.tvFreqDen)).perform(replaceText(den));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,317 @@
|
|||||||
|
/*
|
||||||
|
* 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.espresso;
|
||||||
|
|
||||||
|
import android.app.*;
|
||||||
|
import android.content.*;
|
||||||
|
import android.support.test.*;
|
||||||
|
import android.support.test.espresso.*;
|
||||||
|
import android.support.test.espresso.intent.rule.*;
|
||||||
|
import android.support.test.runner.*;
|
||||||
|
import android.test.suitebuilder.annotation.*;
|
||||||
|
|
||||||
|
import org.hamcrest.*;
|
||||||
|
import org.isoron.uhabits.R;
|
||||||
|
import org.isoron.uhabits.activities.habits.list.*;
|
||||||
|
import org.isoron.uhabits.models.*;
|
||||||
|
import org.isoron.uhabits.utils.*;
|
||||||
|
import org.junit.*;
|
||||||
|
import org.junit.runner.*;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
import static android.support.test.espresso.Espresso.*;
|
||||||
|
import static android.support.test.espresso.Espresso.pressBack;
|
||||||
|
import static android.support.test.espresso.action.ViewActions.*;
|
||||||
|
import static android.support.test.espresso.assertion.ViewAssertions.*;
|
||||||
|
import static android.support.test.espresso.intent.Intents.*;
|
||||||
|
import static android.support.test.espresso.intent.matcher.IntentMatchers.*;
|
||||||
|
import static android.support.test.espresso.matcher.ViewMatchers.*;
|
||||||
|
import static org.hamcrest.Matchers.*;
|
||||||
|
import static org.isoron.uhabits.espresso.HabitViewActions.*;
|
||||||
|
import static org.isoron.uhabits.espresso.MainActivityActions.*;
|
||||||
|
import static org.isoron.uhabits.espresso.ShowHabitActivityActions.*;
|
||||||
|
|
||||||
|
@RunWith(AndroidJUnit4.class)
|
||||||
|
@LargeTest
|
||||||
|
public class MainTest
|
||||||
|
{
|
||||||
|
private SystemHelper sys;
|
||||||
|
|
||||||
|
@Rule
|
||||||
|
public IntentsTestRule<ListHabitsActivity> activityRule =
|
||||||
|
new IntentsTestRule<>(ListHabitsActivity.class);
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setup()
|
||||||
|
{
|
||||||
|
Context context =
|
||||||
|
InstrumentationRegistry.getInstrumentation().getContext();
|
||||||
|
sys = new SystemHelper(context);
|
||||||
|
sys.disableAllAnimations();
|
||||||
|
sys.acquireWakeLock();
|
||||||
|
sys.unlockScreen();
|
||||||
|
|
||||||
|
Instrumentation.ActivityResult okResult =
|
||||||
|
new Instrumentation.ActivityResult(Activity.RESULT_OK,
|
||||||
|
new Intent());
|
||||||
|
|
||||||
|
intending(hasAction(equalTo(Intent.ACTION_SEND))).respondWith(okResult);
|
||||||
|
intending(hasAction(equalTo(Intent.ACTION_SENDTO))).respondWith(
|
||||||
|
okResult);
|
||||||
|
intending(hasAction(equalTo(Intent.ACTION_VIEW))).respondWith(okResult);
|
||||||
|
|
||||||
|
skipTutorial();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void skipTutorial()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
for (int i = 0; i < 10; i++)
|
||||||
|
onView(allOf(withClassName(endsWith("AppCompatImageButton")),
|
||||||
|
isDisplayed())).perform(click());
|
||||||
|
}
|
||||||
|
catch (NoMatchingViewException e)
|
||||||
|
{
|
||||||
|
// ignored
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@After
|
||||||
|
public void tearDown()
|
||||||
|
{
|
||||||
|
sys.releaseWakeLock();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* User opens menu, clicks about, sees about screen.
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testAbout()
|
||||||
|
{
|
||||||
|
clickMenuItem(R.string.about);
|
||||||
|
onView(isRoot()).perform(swipeUp());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* User creates a habit, toggles a bunch of checkmarks, clicks the habit to
|
||||||
|
* open the statistics screen, scrolls down to some views, then scrolls the
|
||||||
|
* views backwards and forwards in time.
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testAddHabitAndViewStats() throws InterruptedException
|
||||||
|
{
|
||||||
|
String name = addHabit(true);
|
||||||
|
|
||||||
|
onData(Matchers.allOf(is(instanceOf(Habit.class)),
|
||||||
|
HabitMatchers.withName(name)))
|
||||||
|
.onChildView(withId(R.id.checkmarkPanel))
|
||||||
|
.perform(toggleAllCheckmarks());
|
||||||
|
|
||||||
|
Thread.sleep(1200);
|
||||||
|
|
||||||
|
onData(Matchers.allOf(is(instanceOf(Habit.class)),
|
||||||
|
HabitMatchers.withName(name)))
|
||||||
|
.onChildView(withId(R.id.label))
|
||||||
|
.perform(click());
|
||||||
|
|
||||||
|
onView(withId(R.id.scoreView)).perform(scrollTo(), swipeRight());
|
||||||
|
|
||||||
|
onView(withId(R.id.frequencyChart)).perform(scrollTo(), swipeRight());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* User opens the app, clicks the add button, types some bogus information,
|
||||||
|
* tries to save, dialog displays an error.
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testAddInvalidHabit()
|
||||||
|
{
|
||||||
|
onView(withId(R.id.actionAdd)).perform(click());
|
||||||
|
|
||||||
|
typeHabitData("", "", "15", "7");
|
||||||
|
|
||||||
|
onView(withId(R.id.buttonSave)).perform(click());
|
||||||
|
onView(withId(R.id.tvName)).check(matches(isDisplayed()));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* User opens the app, creates some habits, selects them, archives them,
|
||||||
|
* select 'show archived' on the menu, selects the previously archived
|
||||||
|
* habits and then deletes them.
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testArchiveHabits()
|
||||||
|
{
|
||||||
|
List<String> names = new LinkedList<>();
|
||||||
|
|
||||||
|
for (int i = 0; i < 3; i++)
|
||||||
|
names.add(addHabit());
|
||||||
|
|
||||||
|
selectHabits(names);
|
||||||
|
|
||||||
|
clickMenuItem(R.string.archive);
|
||||||
|
assertHabitsDontExist(names);
|
||||||
|
|
||||||
|
clickMenuItem(R.string.show_archived);
|
||||||
|
|
||||||
|
assertHabitsExist(names);
|
||||||
|
selectHabits(names);
|
||||||
|
clickMenuItem(R.string.unarchive);
|
||||||
|
|
||||||
|
clickMenuItem(R.string.show_archived);
|
||||||
|
|
||||||
|
assertHabitsExist(names);
|
||||||
|
deleteHabits(names);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* User creates a habit, selects the habit, clicks edit button, changes some
|
||||||
|
* information about the habit, click save button, sees changes on the main
|
||||||
|
* window, selects habit again, changes color, then deletes the habit.
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testEditHabit()
|
||||||
|
{
|
||||||
|
String name = addHabit();
|
||||||
|
|
||||||
|
onData(Matchers.allOf(is(instanceOf(Habit.class)),
|
||||||
|
HabitMatchers.withName(name)))
|
||||||
|
.onChildView(withId(R.id.label))
|
||||||
|
.perform(longClick());
|
||||||
|
|
||||||
|
clickMenuItem(R.string.edit);
|
||||||
|
|
||||||
|
String modifiedName = "Modified " + new Random().nextInt(10000);
|
||||||
|
typeHabitData(modifiedName, "", "1", "1");
|
||||||
|
|
||||||
|
onView(withId(R.id.buttonSave)).perform(click());
|
||||||
|
|
||||||
|
assertHabitExists(modifiedName);
|
||||||
|
|
||||||
|
selectHabit(modifiedName);
|
||||||
|
clickMenuItem(R.string.color_picker_default_title);
|
||||||
|
pressBack();
|
||||||
|
|
||||||
|
deleteHabit(modifiedName);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* User creates a habit, opens statistics page, clicks button to edit
|
||||||
|
* history, adds some checkmarks, closes dialog, sees the modified history
|
||||||
|
* calendar.
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testEditHistory()
|
||||||
|
{
|
||||||
|
String name = addHabit();
|
||||||
|
|
||||||
|
onData(Matchers.allOf(is(instanceOf(Habit.class)),
|
||||||
|
HabitMatchers.withName(name)))
|
||||||
|
.onChildView(withId(R.id.label))
|
||||||
|
.perform(click());
|
||||||
|
|
||||||
|
openHistoryEditor();
|
||||||
|
onView(withClassName(endsWith("HabitHistoryView"))).perform(
|
||||||
|
clickAtRandomLocations(20));
|
||||||
|
|
||||||
|
pressBack();
|
||||||
|
onView(withId(R.id.historyChart)).perform(scrollTo(), swipeRight(),
|
||||||
|
swipeLeft());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* User creates a habit, opens settings, clicks export as CSV, is asked what
|
||||||
|
* activity should handle the file.
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testExportCSV()
|
||||||
|
{
|
||||||
|
addHabit();
|
||||||
|
clickMenuItem(R.string.settings);
|
||||||
|
clickSettingsItem("Export as CSV");
|
||||||
|
intended(hasAction(Intent.ACTION_SEND));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* User creates a habit, exports full backup, deletes the habit, restores
|
||||||
|
* backup, sees that the previously created habit has appeared back.
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testExportImportDB()
|
||||||
|
{
|
||||||
|
String name = addHabit();
|
||||||
|
|
||||||
|
clickMenuItem(R.string.settings);
|
||||||
|
|
||||||
|
String date =
|
||||||
|
DateFormats.getBackupDateFormat().format(DateUtils.getLocalTime());
|
||||||
|
date = date.substring(0, date.length() - 2);
|
||||||
|
|
||||||
|
clickSettingsItem("Export full backup");
|
||||||
|
intended(hasAction(Intent.ACTION_SEND));
|
||||||
|
|
||||||
|
deleteHabit(name);
|
||||||
|
|
||||||
|
clickMenuItem(R.string.settings);
|
||||||
|
clickSettingsItem("Import data");
|
||||||
|
|
||||||
|
onData(
|
||||||
|
allOf(is(instanceOf(String.class)), startsWith("Backups"))).perform(
|
||||||
|
click());
|
||||||
|
|
||||||
|
onData(
|
||||||
|
allOf(is(instanceOf(String.class)), containsString(date))).perform(
|
||||||
|
click());
|
||||||
|
|
||||||
|
selectHabit(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* User opens the settings and generates a bug report.
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testGenerateBugReport()
|
||||||
|
{
|
||||||
|
clickMenuItem(R.string.settings);
|
||||||
|
clickSettingsItem("Generate bug report");
|
||||||
|
intended(hasAction(Intent.ACTION_SEND));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* User opens menu, clicks Help, sees website.
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testHelp()
|
||||||
|
{
|
||||||
|
clickMenuItem(R.string.help);
|
||||||
|
intended(hasAction(Intent.ACTION_VIEW));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* User opens menu, clicks settings, sees settings screen.
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testSettings()
|
||||||
|
{
|
||||||
|
clickMenuItem(R.string.settings);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -17,7 +17,7 @@
|
|||||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.isoron.uhabits.ui;
|
package org.isoron.uhabits.espresso;
|
||||||
|
|
||||||
import android.support.test.espresso.matcher.ViewMatchers;
|
import android.support.test.espresso.matcher.ViewMatchers;
|
||||||
|
|
||||||
@@ -31,7 +31,7 @@ public class ShowHabitActivityActions
|
|||||||
{
|
{
|
||||||
public static void openHistoryEditor()
|
public static void openHistoryEditor()
|
||||||
{
|
{
|
||||||
onView(ViewMatchers.withId(R.id.btEditHistory))
|
onView(ViewMatchers.withId(R.id.edit))
|
||||||
.perform(scrollTo(), click());
|
.perform(scrollTo(), click());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,4 +1,23 @@
|
|||||||
package org.isoron.uhabits.ui;
|
/*
|
||||||
|
* 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.espresso;
|
||||||
|
|
||||||
import android.app.KeyguardManager;
|
import android.app.KeyguardManager;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
@@ -17,80 +17,52 @@
|
|||||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.isoron.uhabits.unit.io;
|
package org.isoron.uhabits.io;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.*;
|
||||||
import android.support.test.InstrumentationRegistry;
|
import android.support.test.*;
|
||||||
import android.support.test.runner.AndroidJUnit4;
|
import android.support.test.runner.*;
|
||||||
import android.test.suitebuilder.annotation.SmallTest;
|
import android.test.suitebuilder.annotation.*;
|
||||||
|
|
||||||
import org.isoron.uhabits.BaseTest;
|
import org.isoron.uhabits.*;
|
||||||
import org.isoron.uhabits.helpers.DatabaseHelper;
|
import org.isoron.uhabits.models.*;
|
||||||
import org.isoron.uhabits.io.HabitsCSVExporter;
|
import org.isoron.uhabits.utils.*;
|
||||||
import org.isoron.uhabits.models.Habit;
|
import org.junit.*;
|
||||||
import org.isoron.uhabits.unit.HabitFixtures;
|
import org.junit.runner.*;
|
||||||
import org.junit.Before;
|
|
||||||
import org.junit.Test;
|
|
||||||
import org.junit.runner.RunWith;
|
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.*;
|
||||||
import java.io.IOException;
|
import java.util.*;
|
||||||
import java.io.InputStream;
|
import java.util.zip.*;
|
||||||
import java.util.Enumeration;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.zip.ZipEntry;
|
|
||||||
import java.util.zip.ZipFile;
|
|
||||||
|
|
||||||
import static junit.framework.Assert.assertTrue;
|
import static junit.framework.Assert.*;
|
||||||
|
|
||||||
@RunWith(AndroidJUnit4.class)
|
@RunWith(AndroidJUnit4.class)
|
||||||
@SmallTest
|
@MediumTest
|
||||||
public class HabitsCSVExporterTest extends BaseTest
|
public class HabitsCSVExporterTest extends BaseAndroidTest
|
||||||
{
|
{
|
||||||
private File baseDir;
|
private File baseDir;
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void setup()
|
public void setUp()
|
||||||
{
|
{
|
||||||
super.setup();
|
super.setUp();
|
||||||
|
|
||||||
HabitFixtures.purgeHabits();
|
fixtures.purgeHabits(habitList);
|
||||||
HabitFixtures.createShortHabit();
|
fixtures.createShortHabit();
|
||||||
HabitFixtures.createEmptyHabit();
|
fixtures.createEmptyHabit();
|
||||||
|
|
||||||
Context targetContext = InstrumentationRegistry.getTargetContext();
|
Context targetContext = InstrumentationRegistry.getTargetContext();
|
||||||
baseDir = targetContext.getCacheDir();
|
baseDir = targetContext.getCacheDir();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void unzip(File file) throws IOException
|
|
||||||
{
|
|
||||||
ZipFile zip = new ZipFile(file);
|
|
||||||
Enumeration<? extends ZipEntry> e = zip.entries();
|
|
||||||
|
|
||||||
while(e.hasMoreElements())
|
|
||||||
{
|
|
||||||
ZipEntry entry = e.nextElement();
|
|
||||||
InputStream stream = zip.getInputStream(entry);
|
|
||||||
|
|
||||||
String outputFilename = String.format("%s/%s", baseDir.getAbsolutePath(),
|
|
||||||
entry.getName());
|
|
||||||
File outputFile = new File(outputFilename);
|
|
||||||
|
|
||||||
File parent = outputFile.getParentFile();
|
|
||||||
if(parent != null) parent.mkdirs();
|
|
||||||
|
|
||||||
DatabaseHelper.copy(stream, outputFile);
|
|
||||||
}
|
|
||||||
|
|
||||||
zip.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testExportCSV() throws IOException
|
public void testExportCSV() throws IOException
|
||||||
{
|
{
|
||||||
List<Habit> habits = Habit.getAll(true);
|
List<Habit> selected = new LinkedList<>();
|
||||||
|
for (Habit h : habitList) selected.add(h);
|
||||||
|
|
||||||
HabitsCSVExporter exporter = new HabitsCSVExporter(habits, baseDir);
|
HabitsCSVExporter exporter =
|
||||||
|
new HabitsCSVExporter(habitList, selected, baseDir);
|
||||||
String filename = exporter.writeArchive();
|
String filename = exporter.writeArchive();
|
||||||
assertAbsolutePathExists(filename);
|
assertAbsolutePathExists(filename);
|
||||||
|
|
||||||
@@ -103,16 +75,45 @@ public class HabitsCSVExporterTest extends BaseTest
|
|||||||
assertPathExists("001 Wake up early/Scores.csv");
|
assertPathExists("001 Wake up early/Scores.csv");
|
||||||
assertPathExists("002 Meditate/Checkmarks.csv");
|
assertPathExists("002 Meditate/Checkmarks.csv");
|
||||||
assertPathExists("002 Meditate/Scores.csv");
|
assertPathExists("002 Meditate/Scores.csv");
|
||||||
}
|
assertPathExists("Checkmarks.csv");
|
||||||
|
assertPathExists("Scores.csv");
|
||||||
private void assertPathExists(String s)
|
|
||||||
{
|
|
||||||
assertAbsolutePathExists(String.format("%s/%s", baseDir.getAbsolutePath(), s));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void assertAbsolutePathExists(String s)
|
private void assertAbsolutePathExists(String s)
|
||||||
{
|
{
|
||||||
File file = new File(s);
|
File file = new File(s);
|
||||||
assertTrue(String.format("File %s should exist", file.getAbsolutePath()), file.exists());
|
assertTrue(
|
||||||
|
String.format("File %s should exist", file.getAbsolutePath()),
|
||||||
|
file.exists());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void assertPathExists(String s)
|
||||||
|
{
|
||||||
|
assertAbsolutePathExists(
|
||||||
|
String.format("%s/%s", baseDir.getAbsolutePath(), s));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void unzip(File file) throws IOException
|
||||||
|
{
|
||||||
|
ZipFile zip = new ZipFile(file);
|
||||||
|
Enumeration<? extends ZipEntry> e = zip.entries();
|
||||||
|
|
||||||
|
while (e.hasMoreElements())
|
||||||
|
{
|
||||||
|
ZipEntry entry = e.nextElement();
|
||||||
|
InputStream stream = zip.getInputStream(entry);
|
||||||
|
|
||||||
|
String outputFilename =
|
||||||
|
String.format("%s/%s", baseDir.getAbsolutePath(),
|
||||||
|
entry.getName());
|
||||||
|
File outputFile = new File(outputFilename);
|
||||||
|
|
||||||
|
File parent = outputFile.getParentFile();
|
||||||
|
if (parent != null) parent.mkdirs();
|
||||||
|
|
||||||
|
FileUtils.copy(stream, outputFile);
|
||||||
|
}
|
||||||
|
|
||||||
|
zip.close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
163
app/src/androidTest/java/org/isoron/uhabits/io/ImportTest.java
Normal file
@@ -0,0 +1,163 @@
|
|||||||
|
/*
|
||||||
|
* 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.io;
|
||||||
|
|
||||||
|
import android.content.*;
|
||||||
|
import android.support.test.*;
|
||||||
|
import android.support.test.runner.*;
|
||||||
|
import android.test.suitebuilder.annotation.*;
|
||||||
|
|
||||||
|
import org.isoron.uhabits.*;
|
||||||
|
import org.isoron.uhabits.models.*;
|
||||||
|
import org.isoron.uhabits.utils.*;
|
||||||
|
import org.junit.*;
|
||||||
|
import org.junit.runner.*;
|
||||||
|
|
||||||
|
import java.io.*;
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
import static org.hamcrest.Matchers.*;
|
||||||
|
import static org.junit.Assert.*;
|
||||||
|
|
||||||
|
@RunWith(AndroidJUnit4.class)
|
||||||
|
@MediumTest
|
||||||
|
public class ImportTest extends BaseAndroidTest
|
||||||
|
{
|
||||||
|
private File baseDir;
|
||||||
|
|
||||||
|
private Context context;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Before
|
||||||
|
public void setUp()
|
||||||
|
{
|
||||||
|
super.setUp();
|
||||||
|
DateUtils.setFixedLocalTime(null);
|
||||||
|
|
||||||
|
fixtures.purgeHabits(habitList);
|
||||||
|
context = InstrumentationRegistry.getInstrumentation().getContext();
|
||||||
|
baseDir = FileUtils.getFilesDir("Backups");
|
||||||
|
if (baseDir == null) fail("baseDir should not be null");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testHabitBullCSV() throws IOException
|
||||||
|
{
|
||||||
|
importFromFile("habitbull.csv");
|
||||||
|
|
||||||
|
assertThat(habitList.size(), equalTo(4));
|
||||||
|
|
||||||
|
Habit habit = habitList.getByPosition(0);
|
||||||
|
assertThat(habit.getName(), equalTo("Breed dragons"));
|
||||||
|
assertThat(habit.getDescription(), equalTo("with love and fire"));
|
||||||
|
assertThat(habit.getFrequency(), equalTo(Frequency.DAILY));
|
||||||
|
assertTrue(containsRepetition(habit, 2016, 3, 18));
|
||||||
|
assertTrue(containsRepetition(habit, 2016, 3, 19));
|
||||||
|
assertFalse(containsRepetition(habit, 2016, 3, 20));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testLoopDB() throws IOException
|
||||||
|
{
|
||||||
|
importFromFile("loop.db");
|
||||||
|
|
||||||
|
assertThat(habitList.size(), equalTo(9));
|
||||||
|
|
||||||
|
Habit habit = habitList.getByPosition(0);
|
||||||
|
assertThat(habit.getName(), equalTo("Wake up early"));
|
||||||
|
assertThat(habit.getFrequency(),
|
||||||
|
equalTo(Frequency.THREE_TIMES_PER_WEEK));
|
||||||
|
assertTrue(containsRepetition(habit, 2016, 3, 14));
|
||||||
|
assertTrue(containsRepetition(habit, 2016, 3, 16));
|
||||||
|
assertFalse(containsRepetition(habit, 2016, 3, 17));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testRewireDB() throws IOException
|
||||||
|
{
|
||||||
|
importFromFile("rewire.db");
|
||||||
|
|
||||||
|
assertThat(habitList.size(), equalTo(3));
|
||||||
|
|
||||||
|
Habit habit = habitList.getByPosition(0);
|
||||||
|
assertThat(habit.getName(), equalTo("Wake up early"));
|
||||||
|
assertThat(habit.getFrequency(),
|
||||||
|
equalTo(Frequency.THREE_TIMES_PER_WEEK));
|
||||||
|
assertFalse(habit.hasReminder());
|
||||||
|
assertFalse(containsRepetition(habit, 2015, 12, 31));
|
||||||
|
assertTrue(containsRepetition(habit, 2016, 1, 18));
|
||||||
|
assertTrue(containsRepetition(habit, 2016, 1, 28));
|
||||||
|
assertFalse(containsRepetition(habit, 2016, 3, 10));
|
||||||
|
|
||||||
|
habit = habitList.getByPosition(1);
|
||||||
|
assertThat(habit.getName(), equalTo("brush teeth"));
|
||||||
|
assertThat(habit.getFrequency(),
|
||||||
|
equalTo(Frequency.THREE_TIMES_PER_WEEK));
|
||||||
|
assertThat(habit.hasReminder(), equalTo(true));
|
||||||
|
|
||||||
|
Reminder reminder = habit.getReminder();
|
||||||
|
assertThat(reminder.getHour(), equalTo(8));
|
||||||
|
assertThat(reminder.getMinute(), equalTo(0));
|
||||||
|
boolean[] reminderDays = { false, true, true, true, true, true, false };
|
||||||
|
assertThat(reminder.getDays().toArray(), equalTo(reminderDays));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testTickmateDB() throws IOException
|
||||||
|
{
|
||||||
|
importFromFile("tickmate.db");
|
||||||
|
|
||||||
|
assertThat(habitList.size(), equalTo(3));
|
||||||
|
|
||||||
|
Habit h = habitList.getByPosition(0);
|
||||||
|
assertThat(h.getName(), equalTo("Vegan"));
|
||||||
|
assertTrue(containsRepetition(h, 2016, 1, 24));
|
||||||
|
assertTrue(containsRepetition(h, 2016, 2, 5));
|
||||||
|
assertTrue(containsRepetition(h, 2016, 3, 18));
|
||||||
|
assertFalse(containsRepetition(h, 2016, 3, 14));
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean containsRepetition(Habit h, int year, int month, int day)
|
||||||
|
{
|
||||||
|
GregorianCalendar date = DateUtils.getStartOfTodayCalendar();
|
||||||
|
date.set(year, month - 1, day);
|
||||||
|
return h.getRepetitions().containsTimestamp(date.getTimeInMillis());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void copyAssetToFile(String assetPath, File dst) throws IOException
|
||||||
|
{
|
||||||
|
InputStream in = context.getAssets().open(assetPath);
|
||||||
|
FileUtils.copy(in, dst);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void importFromFile(String assetFilename) throws IOException
|
||||||
|
{
|
||||||
|
File file =
|
||||||
|
new File(String.format("%s/%s", baseDir.getPath(), assetFilename));
|
||||||
|
copyAssetToFile(assetFilename, file);
|
||||||
|
assertTrue(file.exists());
|
||||||
|
assertTrue(file.canRead());
|
||||||
|
|
||||||
|
GenericImporter importer = component.getGenericImporter();
|
||||||
|
assertThat(importer.canHandle(file), is(true));
|
||||||
|
|
||||||
|
importer.importHabitsFromFile(file);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,87 @@
|
|||||||
|
/*
|
||||||
|
* 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.models.sqlite;
|
||||||
|
|
||||||
|
import android.support.test.runner.*;
|
||||||
|
import android.test.suitebuilder.annotation.*;
|
||||||
|
|
||||||
|
import org.isoron.uhabits.*;
|
||||||
|
import org.isoron.uhabits.models.*;
|
||||||
|
import org.isoron.uhabits.models.sqlite.records.*;
|
||||||
|
import org.junit.*;
|
||||||
|
import org.junit.runner.*;
|
||||||
|
|
||||||
|
import static org.hamcrest.MatcherAssert.*;
|
||||||
|
import static org.hamcrest.core.IsEqual.*;
|
||||||
|
|
||||||
|
@RunWith(AndroidJUnit4.class)
|
||||||
|
@MediumTest
|
||||||
|
public class HabitRecordTest extends BaseAndroidTest
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public void setUp()
|
||||||
|
{
|
||||||
|
super.setUp();
|
||||||
|
|
||||||
|
Habit h = component.getModelFactory().buildHabit();
|
||||||
|
h.setName("Hello world");
|
||||||
|
h.setId(1000L);
|
||||||
|
|
||||||
|
HabitRecord record = new HabitRecord();
|
||||||
|
record.copyFrom(h);
|
||||||
|
record.position = 0;
|
||||||
|
record.save(1000L);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCopyFrom()
|
||||||
|
{
|
||||||
|
Habit habit = component.getModelFactory().buildHabit();
|
||||||
|
habit.setName("Hello world");
|
||||||
|
habit.setDescription("Did you greet the world today?");
|
||||||
|
habit.setColor(1);
|
||||||
|
habit.setArchived(true);
|
||||||
|
habit.setFrequency(Frequency.THREE_TIMES_PER_WEEK);
|
||||||
|
habit.setReminder(new Reminder(8, 30, WeekdayList.EVERY_DAY));
|
||||||
|
habit.setId(1000L);
|
||||||
|
|
||||||
|
HabitRecord rec = new HabitRecord();
|
||||||
|
rec.copyFrom(habit);
|
||||||
|
|
||||||
|
assertThat(rec.name, equalTo(habit.getName()));
|
||||||
|
assertThat(rec.description, equalTo(habit.getDescription()));
|
||||||
|
assertThat(rec.color, equalTo(habit.getColor()));
|
||||||
|
assertThat(rec.archived, equalTo(1));
|
||||||
|
assertThat(rec.freqDen, equalTo(7));
|
||||||
|
assertThat(rec.freqNum, equalTo(3));
|
||||||
|
|
||||||
|
Reminder reminder = habit.getReminder();
|
||||||
|
assertThat(rec.reminderDays, equalTo(reminder.getDays().toInteger()));
|
||||||
|
assertThat(rec.reminderHour, equalTo(reminder.getHour()));
|
||||||
|
assertThat(rec.reminderMin, equalTo(reminder.getMinute()));
|
||||||
|
|
||||||
|
habit.setReminder(null);
|
||||||
|
rec.copyFrom(habit);
|
||||||
|
|
||||||
|
assertThat(rec.reminderMin, equalTo(null));
|
||||||
|
assertThat(rec.reminderHour, equalTo(null));
|
||||||
|
assertThat(rec.reminderDays, equalTo(0));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,127 @@
|
|||||||
|
/*
|
||||||
|
* 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.models.sqlite;
|
||||||
|
|
||||||
|
import android.support.test.runner.*;
|
||||||
|
import android.test.suitebuilder.annotation.*;
|
||||||
|
|
||||||
|
import com.activeandroid.query.*;
|
||||||
|
|
||||||
|
import org.isoron.uhabits.*;
|
||||||
|
import org.isoron.uhabits.models.*;
|
||||||
|
import org.isoron.uhabits.models.sqlite.records.*;
|
||||||
|
import org.isoron.uhabits.utils.*;
|
||||||
|
import org.junit.*;
|
||||||
|
import org.junit.runner.*;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
import static org.hamcrest.MatcherAssert.*;
|
||||||
|
import static org.hamcrest.Matchers.*;
|
||||||
|
|
||||||
|
@RunWith(AndroidJUnit4.class)
|
||||||
|
@MediumTest
|
||||||
|
public class SQLiteCheckmarkListTest extends BaseAndroidTest
|
||||||
|
{
|
||||||
|
private Habit habit;
|
||||||
|
|
||||||
|
private CheckmarkList checkmarks;
|
||||||
|
|
||||||
|
private long today;
|
||||||
|
|
||||||
|
private long day;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setUp()
|
||||||
|
{
|
||||||
|
super.setUp();
|
||||||
|
|
||||||
|
habit = fixtures.createLongHabit();
|
||||||
|
checkmarks = habit.getCheckmarks();
|
||||||
|
checkmarks.getToday(); // compute checkmarks
|
||||||
|
|
||||||
|
today = DateUtils.getStartOfToday();
|
||||||
|
day = DateUtils.millisecondsInOneDay;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testAdd()
|
||||||
|
{
|
||||||
|
checkmarks.invalidateNewerThan(0);
|
||||||
|
|
||||||
|
List<Checkmark> list = new LinkedList<>();
|
||||||
|
list.add(new Checkmark(0, 0));
|
||||||
|
list.add(new Checkmark(1, 1));
|
||||||
|
list.add(new Checkmark(2, 2));
|
||||||
|
|
||||||
|
checkmarks.add(list);
|
||||||
|
|
||||||
|
List<CheckmarkRecord> records = getAllRecords();
|
||||||
|
assertThat(records.size(), equalTo(3));
|
||||||
|
assertThat(records.get(0).timestamp, equalTo(2L));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetByInterval()
|
||||||
|
{
|
||||||
|
long from = today - 10 * day;
|
||||||
|
long to = today - 3 * day;
|
||||||
|
|
||||||
|
List<Checkmark> list = checkmarks.getByInterval(from, to);
|
||||||
|
assertThat(list.size(), equalTo(8));
|
||||||
|
|
||||||
|
assertThat(list.get(0).getTimestamp(), equalTo(today - 3 * day));
|
||||||
|
assertThat(list.get(3).getTimestamp(), equalTo(today - 6 * day));
|
||||||
|
assertThat(list.get(7).getTimestamp(), equalTo(today - 10 * day));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetByInterval_withLongInterval()
|
||||||
|
{
|
||||||
|
long from = today - 200 * day;
|
||||||
|
long to = today;
|
||||||
|
|
||||||
|
List<Checkmark> list = checkmarks.getByInterval(from, to);
|
||||||
|
assertThat(list.size(), equalTo(201));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testInvalidateNewerThan()
|
||||||
|
{
|
||||||
|
List<CheckmarkRecord> records = getAllRecords();
|
||||||
|
assertThat(records.size(), equalTo(121));
|
||||||
|
|
||||||
|
checkmarks.invalidateNewerThan(today - 20 * day);
|
||||||
|
|
||||||
|
records = getAllRecords();
|
||||||
|
assertThat(records.size(), equalTo(100));
|
||||||
|
assertThat(records.get(0).timestamp, equalTo(today - 21 * day));
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<CheckmarkRecord> getAllRecords()
|
||||||
|
{
|
||||||
|
return new Select()
|
||||||
|
.from(CheckmarkRecord.class)
|
||||||
|
.where("habit = ?", habit.getId())
|
||||||
|
.orderBy("timestamp desc")
|
||||||
|
.execute();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,227 @@
|
|||||||
|
/*
|
||||||
|
* 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.models.sqlite;
|
||||||
|
|
||||||
|
import android.support.test.runner.*;
|
||||||
|
import android.test.suitebuilder.annotation.*;
|
||||||
|
|
||||||
|
import com.activeandroid.query.*;
|
||||||
|
|
||||||
|
import org.isoron.uhabits.*;
|
||||||
|
import org.isoron.uhabits.models.*;
|
||||||
|
import org.isoron.uhabits.models.sqlite.records.*;
|
||||||
|
import org.junit.*;
|
||||||
|
import org.junit.rules.*;
|
||||||
|
import org.junit.runner.*;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
import static junit.framework.Assert.*;
|
||||||
|
import static org.hamcrest.MatcherAssert.*;
|
||||||
|
import static org.hamcrest.core.IsEqual.*;
|
||||||
|
|
||||||
|
@SuppressWarnings("JavaDoc")
|
||||||
|
@RunWith(AndroidJUnit4.class)
|
||||||
|
@MediumTest
|
||||||
|
public class SQLiteHabitListTest extends BaseAndroidTest
|
||||||
|
{
|
||||||
|
@Rule
|
||||||
|
public ExpectedException exception = ExpectedException.none();
|
||||||
|
|
||||||
|
private SQLiteHabitList habitList;
|
||||||
|
|
||||||
|
private ModelFactory modelFactory;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setUp()
|
||||||
|
{
|
||||||
|
super.setUp();
|
||||||
|
this.habitList = (SQLiteHabitList) super.habitList;
|
||||||
|
fixtures.purgeHabits(habitList);
|
||||||
|
|
||||||
|
modelFactory = component.getModelFactory();
|
||||||
|
|
||||||
|
for (int i = 0; i < 10; i++)
|
||||||
|
{
|
||||||
|
Habit h = modelFactory.buildHabit();
|
||||||
|
h.setName("habit " + i);
|
||||||
|
h.setId((long) i);
|
||||||
|
if (i % 2 == 0) h.setArchived(true);
|
||||||
|
|
||||||
|
HabitRecord record = new HabitRecord();
|
||||||
|
record.copyFrom(h);
|
||||||
|
record.position = i;
|
||||||
|
record.save(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testAdd_withDuplicate()
|
||||||
|
{
|
||||||
|
Habit habit = modelFactory.buildHabit();
|
||||||
|
habitList.add(habit);
|
||||||
|
exception.expect(IllegalArgumentException.class);
|
||||||
|
habitList.add(habit);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testAdd_withId()
|
||||||
|
{
|
||||||
|
Habit habit = modelFactory.buildHabit();
|
||||||
|
habit.setName("Hello world with id");
|
||||||
|
habit.setId(12300L);
|
||||||
|
|
||||||
|
habitList.add(habit);
|
||||||
|
assertThat(habit.getId(), equalTo(12300L));
|
||||||
|
|
||||||
|
HabitRecord record = getRecord(12300L);
|
||||||
|
assertNotNull(record);
|
||||||
|
assertThat(record.name, equalTo(habit.getName()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testAdd_withoutId()
|
||||||
|
{
|
||||||
|
Habit habit = modelFactory.buildHabit();
|
||||||
|
habit.setName("Hello world");
|
||||||
|
assertNull(habit.getId());
|
||||||
|
|
||||||
|
habitList.add(habit);
|
||||||
|
assertNotNull(habit.getId());
|
||||||
|
|
||||||
|
HabitRecord record = getRecord(habit.getId());
|
||||||
|
assertNotNull(record);
|
||||||
|
assertThat(record.name, equalTo(habit.getName()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSize()
|
||||||
|
{
|
||||||
|
assertThat(habitList.size(), equalTo(10));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetAll_withArchived()
|
||||||
|
{
|
||||||
|
List<Habit> habits = habitList.toList();
|
||||||
|
assertThat(habits.size(), equalTo(10));
|
||||||
|
assertThat(habits.get(3).getName(), equalTo("habit 3"));
|
||||||
|
}
|
||||||
|
|
||||||
|
// @Test
|
||||||
|
// public void testGetAll_withoutArchived()
|
||||||
|
// {
|
||||||
|
// List<Habit> habits = habitList.toList();
|
||||||
|
// assertThat(habits.size(), equalTo(5));
|
||||||
|
// assertThat(habits.get(3).getName(), equalTo("habit 7"));
|
||||||
|
//
|
||||||
|
// List<Habit> another = habitList.toList();
|
||||||
|
// assertThat(habits, equalTo(another));
|
||||||
|
// }
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetById()
|
||||||
|
{
|
||||||
|
Habit h1 = habitList.getById(0);
|
||||||
|
assertNotNull(h1);
|
||||||
|
assertThat(h1.getName(), equalTo("habit 0"));
|
||||||
|
|
||||||
|
Habit h2 = habitList.getById(0);
|
||||||
|
assertNotNull(h2);
|
||||||
|
assertThat(h1, equalTo(h2));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetById_withInvalid()
|
||||||
|
{
|
||||||
|
long invalidId = 9183792001L;
|
||||||
|
Habit h1 = habitList.getById(invalidId);
|
||||||
|
assertNull(h1);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetByPosition()
|
||||||
|
{
|
||||||
|
Habit h = habitList.getByPosition(5);
|
||||||
|
assertNotNull(h);
|
||||||
|
assertThat(h.getName(), equalTo("habit 5"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testIndexOf()
|
||||||
|
{
|
||||||
|
Habit h1 = habitList.getByPosition(5);
|
||||||
|
assertNotNull(h1);
|
||||||
|
assertThat(habitList.indexOf(h1), equalTo(5));
|
||||||
|
|
||||||
|
Habit h2 = modelFactory.buildHabit();
|
||||||
|
assertThat(habitList.indexOf(h2), equalTo(-1));
|
||||||
|
|
||||||
|
h2.setId(1000L);
|
||||||
|
assertThat(habitList.indexOf(h2), equalTo(-1));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test_reorder()
|
||||||
|
{
|
||||||
|
// Same as HabitListTest.java
|
||||||
|
// TODO: remove duplication
|
||||||
|
|
||||||
|
int operations[][] = {
|
||||||
|
{5, 2}, {3, 7}, {4, 4}, {3, 2}
|
||||||
|
};
|
||||||
|
|
||||||
|
int expectedPosition[][] = {
|
||||||
|
{0, 1, 3, 4, 5, 2, 6, 7, 8, 9},
|
||||||
|
{0, 1, 7, 3, 4, 2, 5, 6, 8, 9},
|
||||||
|
{0, 1, 7, 3, 4, 2, 5, 6, 8, 9},
|
||||||
|
{0, 1, 7, 2, 4, 3, 5, 6, 8, 9},
|
||||||
|
};
|
||||||
|
|
||||||
|
for (int i = 0; i < operations.length; i++)
|
||||||
|
{
|
||||||
|
int from = operations[i][0];
|
||||||
|
int to = operations[i][1];
|
||||||
|
|
||||||
|
Habit fromHabit = habitList.getByPosition(from);
|
||||||
|
Habit toHabit = habitList.getByPosition(to);
|
||||||
|
habitList.reorder(fromHabit, toHabit);
|
||||||
|
|
||||||
|
int actualPositions[] = new int[10];
|
||||||
|
|
||||||
|
for (int j = 0; j < 10; j++)
|
||||||
|
{
|
||||||
|
Habit h = habitList.getById(j);
|
||||||
|
assertNotNull(h);
|
||||||
|
actualPositions[j] = habitList.indexOf(h);
|
||||||
|
}
|
||||||
|
|
||||||
|
assertThat(actualPositions, equalTo(expectedPosition[i]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private HabitRecord getRecord(long id)
|
||||||
|
{
|
||||||
|
return new Select()
|
||||||
|
.from(HabitRecord.class)
|
||||||
|
.where("id = ?", id)
|
||||||
|
.executeSingle();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,143 @@
|
|||||||
|
/*
|
||||||
|
* 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.models.sqlite;
|
||||||
|
|
||||||
|
import android.support.annotation.*;
|
||||||
|
import android.support.test.runner.*;
|
||||||
|
import android.test.suitebuilder.annotation.*;
|
||||||
|
|
||||||
|
import com.activeandroid.query.*;
|
||||||
|
|
||||||
|
import org.isoron.uhabits.*;
|
||||||
|
import org.isoron.uhabits.models.*;
|
||||||
|
import org.isoron.uhabits.models.sqlite.records.*;
|
||||||
|
import org.isoron.uhabits.utils.*;
|
||||||
|
import org.junit.*;
|
||||||
|
import org.junit.runner.*;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
import static org.hamcrest.MatcherAssert.*;
|
||||||
|
import static org.hamcrest.Matchers.*;
|
||||||
|
import static org.hamcrest.core.IsNot.not;
|
||||||
|
|
||||||
|
@RunWith(AndroidJUnit4.class)
|
||||||
|
@MediumTest
|
||||||
|
public class SQLiteRepetitionListTest extends BaseAndroidTest
|
||||||
|
{
|
||||||
|
private Habit habit;
|
||||||
|
|
||||||
|
private long today;
|
||||||
|
|
||||||
|
private RepetitionList repetitions;
|
||||||
|
|
||||||
|
private long day;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setUp()
|
||||||
|
{
|
||||||
|
super.setUp();
|
||||||
|
|
||||||
|
habit = fixtures.createLongHabit();
|
||||||
|
repetitions = habit.getRepetitions();
|
||||||
|
today = DateUtils.getStartOfToday();
|
||||||
|
day = DateUtils.millisecondsInOneDay;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testAdd()
|
||||||
|
{
|
||||||
|
RepetitionRecord record = getByTimestamp(today + day);
|
||||||
|
assertThat(record, is(nullValue()));
|
||||||
|
|
||||||
|
Repetition rep = new Repetition(today + day);
|
||||||
|
habit.getRepetitions().add(rep);
|
||||||
|
|
||||||
|
record = getByTimestamp(today + day);
|
||||||
|
assertThat(record, is(not(nullValue())));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetByInterval()
|
||||||
|
{
|
||||||
|
List<Repetition> reps =
|
||||||
|
repetitions.getByInterval(today - 10 * day, today);
|
||||||
|
|
||||||
|
assertThat(reps.size(), equalTo(8));
|
||||||
|
assertThat(reps.get(0).getTimestamp(), equalTo(today - 10 * day));
|
||||||
|
assertThat(reps.get(4).getTimestamp(), equalTo(today - 5 * day));
|
||||||
|
assertThat(reps.get(5).getTimestamp(), equalTo(today - 3 * day));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetByTimestamp()
|
||||||
|
{
|
||||||
|
Repetition rep = repetitions.getByTimestamp(today);
|
||||||
|
assertThat(rep, is(not(nullValue())));
|
||||||
|
assertThat(rep.getTimestamp(), equalTo(today));
|
||||||
|
|
||||||
|
rep = repetitions.getByTimestamp(today - 2 * day);
|
||||||
|
assertThat(rep, is(nullValue()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetOldest()
|
||||||
|
{
|
||||||
|
Repetition rep = repetitions.getOldest();
|
||||||
|
assertThat(rep, is(not(nullValue())));
|
||||||
|
assertThat(rep.getTimestamp(), equalTo(today - 120 * day));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetOldest_withEmptyHabit()
|
||||||
|
{
|
||||||
|
Habit empty = fixtures.createEmptyHabit();
|
||||||
|
Repetition rep = empty.getRepetitions().getOldest();
|
||||||
|
assertThat(rep, is(nullValue()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testRemove()
|
||||||
|
{
|
||||||
|
RepetitionRecord record = getByTimestamp(today);
|
||||||
|
assertThat(record, is(not(nullValue())));
|
||||||
|
|
||||||
|
Repetition rep = record.toRepetition();
|
||||||
|
repetitions.remove(rep);
|
||||||
|
|
||||||
|
record = getByTimestamp(today);
|
||||||
|
assertThat(record, is(nullValue()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
private RepetitionRecord getByTimestamp(long timestamp)
|
||||||
|
{
|
||||||
|
return selectByTimestamp(timestamp).executeSingle();
|
||||||
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
private From selectByTimestamp(long timestamp)
|
||||||
|
{
|
||||||
|
return new Select()
|
||||||
|
.from(RepetitionRecord.class)
|
||||||
|
.where("habit = ?", habit.getId())
|
||||||
|
.and("timestamp = ?", timestamp);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,136 @@
|
|||||||
|
/*
|
||||||
|
* 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.models.sqlite;
|
||||||
|
|
||||||
|
import android.support.test.runner.*;
|
||||||
|
import android.test.suitebuilder.annotation.*;
|
||||||
|
|
||||||
|
import com.activeandroid.query.*;
|
||||||
|
|
||||||
|
import org.isoron.uhabits.*;
|
||||||
|
import org.isoron.uhabits.models.*;
|
||||||
|
import org.isoron.uhabits.models.sqlite.records.*;
|
||||||
|
import org.isoron.uhabits.utils.*;
|
||||||
|
import org.junit.*;
|
||||||
|
import org.junit.runner.*;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
import static org.hamcrest.MatcherAssert.*;
|
||||||
|
import static org.hamcrest.Matchers.*;
|
||||||
|
|
||||||
|
@SuppressWarnings("JavaDoc")
|
||||||
|
@RunWith(AndroidJUnit4.class)
|
||||||
|
@MediumTest
|
||||||
|
public class SQLiteScoreListTest extends BaseAndroidTest
|
||||||
|
{
|
||||||
|
private Habit habit;
|
||||||
|
|
||||||
|
private ScoreList scores;
|
||||||
|
|
||||||
|
private long today;
|
||||||
|
|
||||||
|
private long day;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setUp()
|
||||||
|
{
|
||||||
|
super.setUp();
|
||||||
|
|
||||||
|
habit = fixtures.createLongHabit();
|
||||||
|
scores = habit.getScores();
|
||||||
|
|
||||||
|
today = DateUtils.getStartOfToday();
|
||||||
|
day = DateUtils.millisecondsInOneDay;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetAll()
|
||||||
|
{
|
||||||
|
List<Score> list = scores.toList();
|
||||||
|
assertThat(list.size(), equalTo(121));
|
||||||
|
assertThat(list.get(0).getTimestamp(), equalTo(today));
|
||||||
|
assertThat(list.get(10).getTimestamp(), equalTo(today - 10 * day));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testInvalidateNewerThan()
|
||||||
|
{
|
||||||
|
scores.getTodayValue(); // force recompute
|
||||||
|
List<ScoreRecord> records = getAllRecords();
|
||||||
|
assertThat(records.size(), equalTo(121));
|
||||||
|
|
||||||
|
scores.invalidateNewerThan(today - 10 * day);
|
||||||
|
|
||||||
|
records = getAllRecords();
|
||||||
|
assertThat(records.size(), equalTo(110));
|
||||||
|
assertThat(records.get(0).timestamp, equalTo(today - 11 * day));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testAdd()
|
||||||
|
{
|
||||||
|
new Delete().from(ScoreRecord.class).execute();
|
||||||
|
|
||||||
|
List<Score> list = new LinkedList<>();
|
||||||
|
list.add(new Score(today, 0));
|
||||||
|
list.add(new Score(today - day, 0));
|
||||||
|
list.add(new Score(today - 2 * day, 0));
|
||||||
|
|
||||||
|
scores.add(list);
|
||||||
|
|
||||||
|
List<ScoreRecord> records = getAllRecords();
|
||||||
|
assertThat(records.size(), equalTo(3));
|
||||||
|
assertThat(records.get(0).timestamp, equalTo(today));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetByInterval()
|
||||||
|
{
|
||||||
|
long from = today - 10 * day;
|
||||||
|
long to = today - 3 * day;
|
||||||
|
|
||||||
|
List<Score> list = scores.getByInterval(from, to);
|
||||||
|
assertThat(list.size(), equalTo(8));
|
||||||
|
|
||||||
|
assertThat(list.get(0).getTimestamp(), equalTo(today - 3 * day));
|
||||||
|
assertThat(list.get(3).getTimestamp(), equalTo(today - 6 * day));
|
||||||
|
assertThat(list.get(7).getTimestamp(), equalTo(today - 10 * day));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetByInterval_withLongInterval()
|
||||||
|
{
|
||||||
|
long from = today - 200 * day;
|
||||||
|
long to = today;
|
||||||
|
|
||||||
|
List<Score> list = scores.getByInterval(from, to);
|
||||||
|
assertThat(list.size(), equalTo(201));
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<ScoreRecord> getAllRecords()
|
||||||
|
{
|
||||||
|
return new Select()
|
||||||
|
.from(ScoreRecord.class)
|
||||||
|
.where("habit = ?", habit.getId())
|
||||||
|
.orderBy("timestamp desc")
|
||||||
|
.execute();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,173 @@
|
|||||||
|
/*
|
||||||
|
* 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.pebble;
|
||||||
|
|
||||||
|
import android.content.*;
|
||||||
|
import android.support.annotation.*;
|
||||||
|
import android.support.test.runner.*;
|
||||||
|
import android.test.suitebuilder.annotation.*;
|
||||||
|
|
||||||
|
import com.getpebble.android.kit.*;
|
||||||
|
import com.getpebble.android.kit.util.*;
|
||||||
|
|
||||||
|
import org.isoron.uhabits.*;
|
||||||
|
import org.isoron.uhabits.models.*;
|
||||||
|
import org.isoron.uhabits.receivers.*;
|
||||||
|
import org.json.*;
|
||||||
|
import org.junit.*;
|
||||||
|
import org.junit.runner.*;
|
||||||
|
|
||||||
|
import static com.getpebble.android.kit.Constants.*;
|
||||||
|
import static org.hamcrest.MatcherAssert.*;
|
||||||
|
import static org.hamcrest.core.IsEqual.*;
|
||||||
|
|
||||||
|
@RunWith(AndroidJUnit4.class)
|
||||||
|
@MediumTest
|
||||||
|
public class PebbleReceiverTest extends BaseAndroidTest
|
||||||
|
{
|
||||||
|
|
||||||
|
private Habit habit1;
|
||||||
|
|
||||||
|
private Habit habit2;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setUp()
|
||||||
|
{
|
||||||
|
super.setUp();
|
||||||
|
|
||||||
|
fixtures.purgeHabits(habitList);
|
||||||
|
|
||||||
|
habit1 = fixtures.createEmptyHabit();
|
||||||
|
habit1.setName("Exercise");
|
||||||
|
|
||||||
|
habit2 = fixtures.createEmptyHabit();
|
||||||
|
habit2.setName("Meditate");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCount() throws Exception
|
||||||
|
{
|
||||||
|
onPebbleReceived((dict) -> {
|
||||||
|
assertThat(dict.getString(0), equalTo("COUNT"));
|
||||||
|
assertThat(dict.getInteger(1), equalTo(2L));
|
||||||
|
});
|
||||||
|
|
||||||
|
PebbleDictionary dict = buildCountRequest();
|
||||||
|
sendFromPebbleToAndroid(dict);
|
||||||
|
awaitLatch();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testFetch() throws Exception
|
||||||
|
{
|
||||||
|
onPebbleReceived((dict) -> {
|
||||||
|
assertThat(dict.getString(0), equalTo("HABIT"));
|
||||||
|
assertThat(dict.getInteger(1), equalTo(habit2.getId()));
|
||||||
|
assertThat(dict.getString(2), equalTo(habit2.getName()));
|
||||||
|
assertThat(dict.getInteger(3), equalTo(0L));
|
||||||
|
});
|
||||||
|
|
||||||
|
PebbleDictionary dict = buildFetchRequest(1);
|
||||||
|
sendFromPebbleToAndroid(dict);
|
||||||
|
awaitLatch();
|
||||||
|
}
|
||||||
|
|
||||||
|
// @Test
|
||||||
|
// public void testToggle() throws Exception
|
||||||
|
// {
|
||||||
|
// int v = habit1.getCheckmarks().getTodayValue();
|
||||||
|
// assertThat(v, equalTo(Checkmark.UNCHECKED));
|
||||||
|
//
|
||||||
|
// onPebbleReceived((dict) -> {
|
||||||
|
// assertThat(dict.getString(0), equalTo("OK"));
|
||||||
|
// int value = habit1.getCheckmarks().getTodayValue();
|
||||||
|
// assertThat(value, equalTo(200)); //Checkmark.CHECKED_EXPLICITLY));
|
||||||
|
// });
|
||||||
|
//
|
||||||
|
// PebbleDictionary dict = buildToggleRequest(habit1.getId());
|
||||||
|
// sendFromPebbleToAndroid(dict);
|
||||||
|
// awaitLatch();
|
||||||
|
// }
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
protected PebbleDictionary buildCountRequest()
|
||||||
|
{
|
||||||
|
PebbleDictionary dict = new PebbleDictionary();
|
||||||
|
dict.addString(0, "COUNT");
|
||||||
|
return dict;
|
||||||
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
protected PebbleDictionary buildFetchRequest(int position)
|
||||||
|
{
|
||||||
|
PebbleDictionary dict = new PebbleDictionary();
|
||||||
|
dict.addString(0, "FETCH");
|
||||||
|
dict.addInt32(1, position);
|
||||||
|
return dict;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void onPebbleReceived(PebbleProcessor processor)
|
||||||
|
{
|
||||||
|
BroadcastReceiver pebbleReceiver = new BroadcastReceiver()
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public void onReceive(Context context, Intent intent)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
String jsonData = intent.getStringExtra(MSG_DATA);
|
||||||
|
PebbleDictionary dict = PebbleDictionary.fromJson(jsonData);
|
||||||
|
processor.process(dict);
|
||||||
|
latch.countDown();
|
||||||
|
targetContext.unregisterReceiver(this);
|
||||||
|
}
|
||||||
|
catch (JSONException e)
|
||||||
|
{
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
IntentFilter filter = new IntentFilter(Constants.INTENT_APP_SEND);
|
||||||
|
targetContext.registerReceiver(pebbleReceiver, filter);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void sendFromPebbleToAndroid(PebbleDictionary dict)
|
||||||
|
{
|
||||||
|
Intent intent = new Intent(Constants.INTENT_APP_RECEIVE);
|
||||||
|
intent.putExtra(Constants.APP_UUID, PebbleReceiver.WATCHAPP_UUID);
|
||||||
|
intent.putExtra(Constants.TRANSACTION_ID, 0);
|
||||||
|
intent.putExtra(Constants.MSG_DATA, dict.toJsonString());
|
||||||
|
targetContext.sendBroadcast(intent);
|
||||||
|
}
|
||||||
|
|
||||||
|
private PebbleDictionary buildToggleRequest(long habitId)
|
||||||
|
{
|
||||||
|
PebbleDictionary dict = new PebbleDictionary();
|
||||||
|
dict.addString(0, "TOGGLE");
|
||||||
|
dict.addInt32(1, (int) habitId);
|
||||||
|
return dict;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface PebbleProcessor
|
||||||
|
{
|
||||||
|
void process(PebbleDictionary dict);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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.tasks;
|
||||||
|
|
||||||
|
import android.support.test.runner.*;
|
||||||
|
import android.test.suitebuilder.annotation.*;
|
||||||
|
|
||||||
|
import org.isoron.uhabits.*;
|
||||||
|
import org.isoron.uhabits.models.*;
|
||||||
|
import org.junit.*;
|
||||||
|
import org.junit.runner.*;
|
||||||
|
|
||||||
|
import java.io.*;
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
import static junit.framework.Assert.*;
|
||||||
|
import static org.hamcrest.MatcherAssert.*;
|
||||||
|
import static org.hamcrest.Matchers.*;
|
||||||
|
import static org.hamcrest.core.IsNot.not;
|
||||||
|
|
||||||
|
@RunWith(AndroidJUnit4.class)
|
||||||
|
@MediumTest
|
||||||
|
public class ExportCSVTaskTest extends BaseAndroidTest
|
||||||
|
{
|
||||||
|
@Before
|
||||||
|
@Override
|
||||||
|
public void setUp()
|
||||||
|
{
|
||||||
|
super.setUp();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testExportCSV() throws Throwable
|
||||||
|
{
|
||||||
|
fixtures.purgeHabits(habitList);
|
||||||
|
fixtures.createShortHabit();
|
||||||
|
|
||||||
|
List<Habit> selected = new LinkedList<>();
|
||||||
|
for (Habit h : habitList) selected.add(h);
|
||||||
|
|
||||||
|
taskRunner.execute(
|
||||||
|
new ExportCSVTask(habitList, selected, archiveFilename -> {
|
||||||
|
assertThat(archiveFilename, is(not(nullValue())));
|
||||||
|
File f = new File(archiveFilename);
|
||||||
|
assertTrue(f.exists());
|
||||||
|
assertTrue(f.canRead());
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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.tasks;
|
||||||
|
|
||||||
|
import android.support.test.runner.*;
|
||||||
|
import android.test.suitebuilder.annotation.*;
|
||||||
|
|
||||||
|
import org.isoron.uhabits.*;
|
||||||
|
import org.junit.*;
|
||||||
|
import org.junit.runner.*;
|
||||||
|
|
||||||
|
import java.io.*;
|
||||||
|
|
||||||
|
import static junit.framework.Assert.*;
|
||||||
|
import static org.hamcrest.MatcherAssert.*;
|
||||||
|
import static org.hamcrest.Matchers.*;
|
||||||
|
import static org.hamcrest.core.IsNot.not;
|
||||||
|
|
||||||
|
@RunWith(AndroidJUnit4.class)
|
||||||
|
@MediumTest
|
||||||
|
public class ExportDBTaskTest extends BaseAndroidTest
|
||||||
|
{
|
||||||
|
@Before
|
||||||
|
public void setUp()
|
||||||
|
{
|
||||||
|
super.setUp();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testExportCSV() throws Throwable
|
||||||
|
{
|
||||||
|
ExportDBTask task = new ExportDBTask(filename -> {
|
||||||
|
assertThat(filename, is(not(nullValue())));
|
||||||
|
|
||||||
|
File f = new File(filename);
|
||||||
|
assertTrue(f.exists());
|
||||||
|
assertTrue(f.canRead());
|
||||||
|
});
|
||||||
|
|
||||||
|
taskRunner.execute(task);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,225 +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.ui;
|
|
||||||
|
|
||||||
import android.support.test.espresso.NoMatchingViewException;
|
|
||||||
import android.support.test.espresso.contrib.RecyclerViewActions;
|
|
||||||
|
|
||||||
import org.isoron.uhabits.R;
|
|
||||||
import org.isoron.uhabits.models.Habit;
|
|
||||||
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.LinkedList;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Random;
|
|
||||||
|
|
||||||
import static android.support.test.espresso.Espresso.onData;
|
|
||||||
import static android.support.test.espresso.Espresso.onView;
|
|
||||||
import static android.support.test.espresso.Espresso.pressBack;
|
|
||||||
import static android.support.test.espresso.action.ViewActions.click;
|
|
||||||
import static android.support.test.espresso.action.ViewActions.longClick;
|
|
||||||
import static android.support.test.espresso.action.ViewActions.replaceText;
|
|
||||||
import static android.support.test.espresso.assertion.ViewAssertions.matches;
|
|
||||||
import static android.support.test.espresso.matcher.RootMatchers.isPlatformPopup;
|
|
||||||
import static android.support.test.espresso.matcher.ViewMatchers.Visibility.VISIBLE;
|
|
||||||
import static android.support.test.espresso.matcher.ViewMatchers.hasDescendant;
|
|
||||||
import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed;
|
|
||||||
import static android.support.test.espresso.matcher.ViewMatchers.withClassName;
|
|
||||||
import static android.support.test.espresso.matcher.ViewMatchers.withContentDescription;
|
|
||||||
import static android.support.test.espresso.matcher.ViewMatchers.withEffectiveVisibility;
|
|
||||||
import static android.support.test.espresso.matcher.ViewMatchers.withId;
|
|
||||||
import static android.support.test.espresso.matcher.ViewMatchers.withParent;
|
|
||||||
import static android.support.test.espresso.matcher.ViewMatchers.withText;
|
|
||||||
import static org.hamcrest.Matchers.allOf;
|
|
||||||
import static org.hamcrest.Matchers.containsString;
|
|
||||||
import static org.hamcrest.Matchers.instanceOf;
|
|
||||||
import static org.hamcrest.Matchers.is;
|
|
||||||
import static org.hamcrest.Matchers.not;
|
|
||||||
import static org.hamcrest.Matchers.startsWith;
|
|
||||||
import static org.isoron.uhabits.ui.HabitMatchers.containsHabit;
|
|
||||||
import static org.isoron.uhabits.ui.HabitMatchers.withName;
|
|
||||||
|
|
||||||
public class MainActivityActions
|
|
||||||
{
|
|
||||||
public static String addHabit()
|
|
||||||
{
|
|
||||||
return addHabit(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static String addHabit(boolean openDialogs)
|
|
||||||
{
|
|
||||||
String name = "New Habit " + new Random().nextInt(1000000);
|
|
||||||
String description = "Did you perform your new habit today?";
|
|
||||||
String num = "4";
|
|
||||||
String den = "8";
|
|
||||||
|
|
||||||
onView(withId(R.id.action_add))
|
|
||||||
.perform(click());
|
|
||||||
|
|
||||||
typeHabitData(name, description, num, den);
|
|
||||||
|
|
||||||
if(openDialogs)
|
|
||||||
{
|
|
||||||
onView(withId(R.id.buttonPickColor))
|
|
||||||
.perform(click());
|
|
||||||
pressBack();
|
|
||||||
onView(withId(R.id.inputReminderTime))
|
|
||||||
.perform(click());
|
|
||||||
onView(withText("Done"))
|
|
||||||
.perform(click());
|
|
||||||
onView(withId(R.id.inputReminderDays))
|
|
||||||
.perform(click());
|
|
||||||
onView(withText("OK"))
|
|
||||||
.perform(click());
|
|
||||||
}
|
|
||||||
|
|
||||||
onView(withId(R.id.buttonSave))
|
|
||||||
.perform(click());
|
|
||||||
|
|
||||||
onData(allOf(is(instanceOf(Habit.class)), withName(name)))
|
|
||||||
.onChildView(withId(R.id.label));
|
|
||||||
|
|
||||||
return name;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void typeHabitData(String name, String description, String num, String den)
|
|
||||||
{
|
|
||||||
onView(withId(R.id.input_name))
|
|
||||||
.perform(replaceText(name));
|
|
||||||
onView(withId(R.id.input_description))
|
|
||||||
.perform(replaceText(description));
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
onView(allOf(withId(R.id.sFrequency), withEffectiveVisibility(VISIBLE)))
|
|
||||||
.perform(click());
|
|
||||||
onData(allOf(instanceOf(String.class), startsWith("Custom")))
|
|
||||||
.inRoot(isPlatformPopup())
|
|
||||||
.perform(click());
|
|
||||||
}
|
|
||||||
catch(NoMatchingViewException e)
|
|
||||||
{
|
|
||||||
// ignored
|
|
||||||
}
|
|
||||||
|
|
||||||
onView(withId(R.id.input_freq_num))
|
|
||||||
.perform(replaceText(num));
|
|
||||||
onView(withId(R.id.input_freq_den))
|
|
||||||
.perform(replaceText(den));
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void selectHabit(String name)
|
|
||||||
{
|
|
||||||
selectHabits(Collections.singletonList(name));
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void selectHabits(List<String> names)
|
|
||||||
{
|
|
||||||
boolean first = true;
|
|
||||||
for(String name : names)
|
|
||||||
{
|
|
||||||
onData(allOf(is(instanceOf(Habit.class)), withName(name)))
|
|
||||||
.onChildView(withId(R.id.label))
|
|
||||||
.perform(first ? longClick() : click());
|
|
||||||
|
|
||||||
first = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void assertHabitsDontExist(List<String> names)
|
|
||||||
{
|
|
||||||
for(String name : names)
|
|
||||||
onView(withId(R.id.listView))
|
|
||||||
.check(matches(not(containsHabit(withName(name)))));
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void assertHabitExists(String name)
|
|
||||||
{
|
|
||||||
List<String> names = new LinkedList<>();
|
|
||||||
names.add(name);
|
|
||||||
assertHabitsExist(names);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void assertHabitsExist(List<String> names)
|
|
||||||
{
|
|
||||||
for(String name : names)
|
|
||||||
onData(allOf(is(instanceOf(Habit.class)), withName(name)))
|
|
||||||
.check(matches(isDisplayed()));
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void deleteHabit(String name)
|
|
||||||
{
|
|
||||||
deleteHabits(Collections.singletonList(name));
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void deleteHabits(List<String> names)
|
|
||||||
{
|
|
||||||
selectHabits(names);
|
|
||||||
clickMenuItem(R.string.delete);
|
|
||||||
onView(withText("OK"))
|
|
||||||
.perform(click());
|
|
||||||
assertHabitsDontExist(names);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void clickMenuItem(int stringId)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
onView(withText(stringId)).perform(click());
|
|
||||||
}
|
|
||||||
catch (Exception e1)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
onView(withContentDescription(stringId)).perform(click());
|
|
||||||
}
|
|
||||||
catch(Exception e2)
|
|
||||||
{
|
|
||||||
clickHiddenMenuItem(stringId);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void clickHiddenMenuItem(int stringId)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
// Try the ActionMode overflow menu first
|
|
||||||
onView(allOf(withContentDescription("More options"), withParent(withParent(
|
|
||||||
withClassName(containsString("Action")))))).perform(click());
|
|
||||||
}
|
|
||||||
catch (Exception e1)
|
|
||||||
{
|
|
||||||
// Try the toolbar overflow menu
|
|
||||||
onView(allOf(withContentDescription("More options"), withParent(withParent(
|
|
||||||
withClassName(containsString("Toolbar")))))).perform(click());
|
|
||||||
}
|
|
||||||
|
|
||||||
onView(withText(stringId)).perform(click());
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void clickSettingsItem(String text)
|
|
||||||
{
|
|
||||||
onView(withClassName(containsString("RecyclerView")))
|
|
||||||
.perform(RecyclerViewActions.actionOnItem(
|
|
||||||
hasDescendant(withText(containsString(text))),
|
|
||||||
click()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,346 +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.ui;
|
|
||||||
|
|
||||||
import android.app.Activity;
|
|
||||||
import android.app.Instrumentation;
|
|
||||||
import android.content.Context;
|
|
||||||
import android.content.Intent;
|
|
||||||
import android.support.test.InstrumentationRegistry;
|
|
||||||
import android.support.test.espresso.NoMatchingViewException;
|
|
||||||
import android.support.test.espresso.intent.rule.IntentsTestRule;
|
|
||||||
import android.support.test.runner.AndroidJUnit4;
|
|
||||||
import android.test.suitebuilder.annotation.LargeTest;
|
|
||||||
|
|
||||||
import org.isoron.uhabits.MainActivity;
|
|
||||||
import org.isoron.uhabits.R;
|
|
||||||
import org.isoron.uhabits.helpers.DateHelper;
|
|
||||||
import org.isoron.uhabits.models.Habit;
|
|
||||||
import org.junit.After;
|
|
||||||
import org.junit.Before;
|
|
||||||
import org.junit.Rule;
|
|
||||||
import org.junit.Test;
|
|
||||||
import org.junit.runner.RunWith;
|
|
||||||
|
|
||||||
import java.util.LinkedList;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Random;
|
|
||||||
|
|
||||||
import static android.support.test.espresso.Espresso.onData;
|
|
||||||
import static android.support.test.espresso.Espresso.onView;
|
|
||||||
import static android.support.test.espresso.Espresso.pressBack;
|
|
||||||
import static android.support.test.espresso.action.ViewActions.click;
|
|
||||||
import static android.support.test.espresso.action.ViewActions.longClick;
|
|
||||||
import static android.support.test.espresso.action.ViewActions.scrollTo;
|
|
||||||
import static android.support.test.espresso.action.ViewActions.swipeLeft;
|
|
||||||
import static android.support.test.espresso.action.ViewActions.swipeRight;
|
|
||||||
import static android.support.test.espresso.action.ViewActions.swipeUp;
|
|
||||||
import static android.support.test.espresso.assertion.ViewAssertions.matches;
|
|
||||||
import static android.support.test.espresso.intent.Intents.intended;
|
|
||||||
import static android.support.test.espresso.intent.Intents.intending;
|
|
||||||
import static android.support.test.espresso.intent.matcher.IntentMatchers.hasAction;
|
|
||||||
import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed;
|
|
||||||
import static android.support.test.espresso.matcher.ViewMatchers.isRoot;
|
|
||||||
import static android.support.test.espresso.matcher.ViewMatchers.withClassName;
|
|
||||||
import static android.support.test.espresso.matcher.ViewMatchers.withId;
|
|
||||||
import static org.hamcrest.Matchers.allOf;
|
|
||||||
import static org.hamcrest.Matchers.containsString;
|
|
||||||
import static org.hamcrest.Matchers.endsWith;
|
|
||||||
import static org.hamcrest.Matchers.equalTo;
|
|
||||||
import static org.hamcrest.Matchers.instanceOf;
|
|
||||||
import static org.hamcrest.Matchers.is;
|
|
||||||
import static org.hamcrest.Matchers.startsWith;
|
|
||||||
import static org.isoron.uhabits.ui.HabitMatchers.withName;
|
|
||||||
import static org.isoron.uhabits.ui.HabitViewActions.clickAtRandomLocations;
|
|
||||||
import static org.isoron.uhabits.ui.HabitViewActions.toggleAllCheckmarks;
|
|
||||||
import static org.isoron.uhabits.ui.MainActivityActions.addHabit;
|
|
||||||
import static org.isoron.uhabits.ui.MainActivityActions.assertHabitExists;
|
|
||||||
import static org.isoron.uhabits.ui.MainActivityActions.assertHabitsDontExist;
|
|
||||||
import static org.isoron.uhabits.ui.MainActivityActions.assertHabitsExist;
|
|
||||||
import static org.isoron.uhabits.ui.MainActivityActions.clickMenuItem;
|
|
||||||
import static org.isoron.uhabits.ui.MainActivityActions.clickSettingsItem;
|
|
||||||
import static org.isoron.uhabits.ui.MainActivityActions.deleteHabit;
|
|
||||||
import static org.isoron.uhabits.ui.MainActivityActions.deleteHabits;
|
|
||||||
import static org.isoron.uhabits.ui.MainActivityActions.selectHabit;
|
|
||||||
import static org.isoron.uhabits.ui.MainActivityActions.selectHabits;
|
|
||||||
import static org.isoron.uhabits.ui.MainActivityActions.typeHabitData;
|
|
||||||
import static org.isoron.uhabits.ui.ShowHabitActivityActions.openHistoryEditor;
|
|
||||||
|
|
||||||
@RunWith(AndroidJUnit4.class)
|
|
||||||
@LargeTest
|
|
||||||
public class MainTest
|
|
||||||
{
|
|
||||||
private SystemHelper sys;
|
|
||||||
|
|
||||||
@Rule
|
|
||||||
public IntentsTestRule<MainActivity> activityRule = new IntentsTestRule<>(
|
|
||||||
MainActivity.class);
|
|
||||||
|
|
||||||
private Context targetContext;
|
|
||||||
|
|
||||||
@Before
|
|
||||||
public void setup()
|
|
||||||
{
|
|
||||||
Context context = InstrumentationRegistry.getInstrumentation().getContext();
|
|
||||||
sys = new SystemHelper(context);
|
|
||||||
sys.disableAllAnimations();
|
|
||||||
sys.acquireWakeLock();
|
|
||||||
sys.unlockScreen();
|
|
||||||
|
|
||||||
targetContext = InstrumentationRegistry.getTargetContext();
|
|
||||||
|
|
||||||
Instrumentation.ActivityResult okResult = new Instrumentation.ActivityResult(
|
|
||||||
Activity.RESULT_OK, new Intent());
|
|
||||||
|
|
||||||
intending(hasAction(equalTo(Intent.ACTION_SEND))).respondWith(okResult);
|
|
||||||
intending(hasAction(equalTo(Intent.ACTION_SENDTO))).respondWith(okResult);
|
|
||||||
intending(hasAction(equalTo(Intent.ACTION_VIEW))).respondWith(okResult);
|
|
||||||
|
|
||||||
skipTutorial();
|
|
||||||
}
|
|
||||||
|
|
||||||
@After
|
|
||||||
public void tearDown()
|
|
||||||
{
|
|
||||||
sys.releaseWakeLock();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void skipTutorial()
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
for (int i = 0; i < 10; i++)
|
|
||||||
onView(allOf(withClassName(endsWith("AppCompatImageButton")),
|
|
||||||
isDisplayed())).perform(click());
|
|
||||||
}
|
|
||||||
catch (NoMatchingViewException e)
|
|
||||||
{
|
|
||||||
// ignored
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* User opens the app, creates some habits, selects them, archives them, select 'show archived'
|
|
||||||
* on the menu, selects the previously archived habits and then deletes them.
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
public void testArchiveHabits()
|
|
||||||
{
|
|
||||||
List<String> names = new LinkedList<>();
|
|
||||||
|
|
||||||
for(int i = 0; i < 3; i++)
|
|
||||||
names.add(addHabit());
|
|
||||||
|
|
||||||
selectHabits(names);
|
|
||||||
|
|
||||||
clickMenuItem(R.string.archive);
|
|
||||||
assertHabitsDontExist(names);
|
|
||||||
|
|
||||||
clickMenuItem(R.string.show_archived);
|
|
||||||
|
|
||||||
assertHabitsExist(names);
|
|
||||||
selectHabits(names);
|
|
||||||
clickMenuItem(R.string.unarchive);
|
|
||||||
|
|
||||||
clickMenuItem(R.string.show_archived);
|
|
||||||
|
|
||||||
assertHabitsExist(names);
|
|
||||||
deleteHabits(names);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* User opens the app, clicks the add button, types some bogus information, tries to save,
|
|
||||||
* dialog displays an error.
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
public void testAddInvalidHabit()
|
|
||||||
{
|
|
||||||
onView(withId(R.id.action_add))
|
|
||||||
.perform(click());
|
|
||||||
|
|
||||||
typeHabitData("", "", "15", "7");
|
|
||||||
|
|
||||||
onView(withId(R.id.buttonSave)).perform(click());
|
|
||||||
onView(withId(R.id.input_name)).check(matches(isDisplayed()));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* User creates a habit, toggles a bunch of checkmarks, clicks the habit to open the statistics
|
|
||||||
* screen, scrolls down to some views, then scrolls the views backwards and forwards in time.
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
public void testAddHabitAndViewStats() throws InterruptedException
|
|
||||||
{
|
|
||||||
String name = addHabit(true);
|
|
||||||
|
|
||||||
onData(allOf(is(instanceOf(Habit.class)), withName(name)))
|
|
||||||
.onChildView(withId(R.id.llButtons))
|
|
||||||
.perform(toggleAllCheckmarks());
|
|
||||||
|
|
||||||
Thread.sleep(1200);
|
|
||||||
|
|
||||||
onData(allOf(is(instanceOf(Habit.class)), withName(name)))
|
|
||||||
.onChildView(withId(R.id.label))
|
|
||||||
.perform(click());
|
|
||||||
|
|
||||||
onView(withId(R.id.scoreView))
|
|
||||||
.perform(scrollTo(), swipeRight());
|
|
||||||
|
|
||||||
onView(withId(R.id.punchcardView))
|
|
||||||
.perform(scrollTo(), swipeRight());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* User creates a habit, selects the habit, clicks edit button, changes some information about
|
|
||||||
* the habit, click save button, sees changes on the main window, selects habit again,
|
|
||||||
* changes color, then deletes the habit.
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
public void testEditHabit()
|
|
||||||
{
|
|
||||||
String name = addHabit();
|
|
||||||
|
|
||||||
onData(allOf(is(instanceOf(Habit.class)), withName(name)))
|
|
||||||
.onChildView(withId(R.id.label))
|
|
||||||
.perform(longClick());
|
|
||||||
|
|
||||||
clickMenuItem(R.string.edit);
|
|
||||||
|
|
||||||
String modifiedName = "Modified " + new Random().nextInt(10000);
|
|
||||||
typeHabitData(modifiedName, "", "1", "1");
|
|
||||||
|
|
||||||
onView(withId(R.id.buttonSave))
|
|
||||||
.perform(click());
|
|
||||||
|
|
||||||
assertHabitExists(modifiedName);
|
|
||||||
|
|
||||||
selectHabit(modifiedName);
|
|
||||||
clickMenuItem(R.string.color_picker_default_title);
|
|
||||||
pressBack();
|
|
||||||
|
|
||||||
deleteHabit(modifiedName);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* User creates a habit, opens statistics page, clicks button to edit history, adds some
|
|
||||||
* checkmarks, closes dialog, sees the modified history calendar.
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
public void testEditHistory()
|
|
||||||
{
|
|
||||||
String name = addHabit();
|
|
||||||
|
|
||||||
onData(allOf(is(instanceOf(Habit.class)), withName(name)))
|
|
||||||
.onChildView(withId(R.id.label))
|
|
||||||
.perform(click());
|
|
||||||
|
|
||||||
openHistoryEditor();
|
|
||||||
onView(withClassName(endsWith("HabitHistoryView")))
|
|
||||||
.perform(clickAtRandomLocations(20));
|
|
||||||
|
|
||||||
pressBack();
|
|
||||||
onView(withId(R.id.historyView))
|
|
||||||
.perform(scrollTo(), swipeRight(), swipeLeft());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* User opens menu, clicks settings, sees settings screen.
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
public void testSettings()
|
|
||||||
{
|
|
||||||
clickMenuItem(R.string.settings);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* User opens menu, clicks about, sees about screen.
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
public void testAbout()
|
|
||||||
{
|
|
||||||
clickMenuItem(R.string.about);
|
|
||||||
onView(isRoot()).perform(swipeUp());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* User opens menu, clicks Help, sees website.
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
public void testHelp()
|
|
||||||
{
|
|
||||||
clickMenuItem(R.string.help);
|
|
||||||
intended(hasAction(Intent.ACTION_VIEW));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* User creates a habit, exports full backup, deletes the habit, restores backup, sees that the
|
|
||||||
* previously created habit has appeared back.
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
public void testExportImportDB()
|
|
||||||
{
|
|
||||||
String name = addHabit();
|
|
||||||
|
|
||||||
clickMenuItem(R.string.settings);
|
|
||||||
|
|
||||||
String date = DateHelper.getBackupDateFormat().format(DateHelper.getLocalTime());
|
|
||||||
date = date.substring(0, date.length() - 2);
|
|
||||||
|
|
||||||
clickSettingsItem("Export full backup");
|
|
||||||
intended(hasAction(Intent.ACTION_SEND));
|
|
||||||
|
|
||||||
deleteHabit(name);
|
|
||||||
|
|
||||||
clickMenuItem(R.string.settings);
|
|
||||||
clickSettingsItem("Import data");
|
|
||||||
|
|
||||||
onData(allOf(is(instanceOf(String.class)), startsWith("Backups")))
|
|
||||||
.perform(click());
|
|
||||||
|
|
||||||
onData(allOf(is(instanceOf(String.class)), containsString(date)))
|
|
||||||
.perform(click());
|
|
||||||
|
|
||||||
selectHabit(name);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* User creates a habit, opens settings, clicks export as CSV, is asked what activity should
|
|
||||||
* handle the file.
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
public void testExportCSV()
|
|
||||||
{
|
|
||||||
addHabit();
|
|
||||||
clickMenuItem(R.string.settings);
|
|
||||||
clickSettingsItem("Export as CSV");
|
|
||||||
intended(hasAction(Intent.ACTION_SEND));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* User opens the settings and generates a bug report.
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
public void testGenerateBugReport()
|
|
||||||
{
|
|
||||||
clickMenuItem(R.string.settings);
|
|
||||||
clickSettingsItem("Generate bug report");
|
|
||||||
intended(hasAction(Intent.ACTION_SENDTO));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,168 +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.unit;
|
|
||||||
|
|
||||||
import android.content.Context;
|
|
||||||
import android.support.annotation.Nullable;
|
|
||||||
import android.util.Log;
|
|
||||||
|
|
||||||
import org.isoron.uhabits.helpers.DatabaseHelper;
|
|
||||||
import org.isoron.uhabits.helpers.DateHelper;
|
|
||||||
import org.isoron.uhabits.models.Habit;
|
|
||||||
import org.isoron.uhabits.tasks.BaseTask;
|
|
||||||
import org.isoron.uhabits.tasks.ExportDBTask;
|
|
||||||
import org.isoron.uhabits.tasks.ImportDataTask;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.util.Random;
|
|
||||||
|
|
||||||
import static org.junit.Assert.fail;
|
|
||||||
|
|
||||||
public class HabitFixtures
|
|
||||||
{
|
|
||||||
public static boolean NON_DAILY_HABIT_CHECKS[] = { true, false, false, true, true, true, false,
|
|
||||||
false, true, true };
|
|
||||||
|
|
||||||
public static Habit createShortHabit()
|
|
||||||
{
|
|
||||||
Habit habit = new Habit();
|
|
||||||
habit.name = "Wake up early";
|
|
||||||
habit.description = "Did you wake up before 6am?";
|
|
||||||
habit.freqNum = 2;
|
|
||||||
habit.freqDen = 3;
|
|
||||||
habit.save();
|
|
||||||
|
|
||||||
long timestamp = DateHelper.getStartOfToday();
|
|
||||||
for(boolean c : NON_DAILY_HABIT_CHECKS)
|
|
||||||
{
|
|
||||||
if(c) habit.repetitions.toggle(timestamp);
|
|
||||||
timestamp -= DateHelper.millisecondsInOneDay;
|
|
||||||
}
|
|
||||||
|
|
||||||
return habit;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Habit createEmptyHabit()
|
|
||||||
{
|
|
||||||
Habit habit = new Habit();
|
|
||||||
habit.name = "Meditate";
|
|
||||||
habit.description = "Did you meditate this morning?";
|
|
||||||
habit.color = 3;
|
|
||||||
habit.freqNum = 1;
|
|
||||||
habit.freqDen = 1;
|
|
||||||
habit.save();
|
|
||||||
return habit;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Habit createLongHabit()
|
|
||||||
{
|
|
||||||
Habit habit = createEmptyHabit();
|
|
||||||
habit.freqNum = 3;
|
|
||||||
habit.freqDen = 7;
|
|
||||||
habit.color = 4;
|
|
||||||
habit.save();
|
|
||||||
|
|
||||||
long day = DateHelper.millisecondsInOneDay;
|
|
||||||
long today = DateHelper.getStartOfToday();
|
|
||||||
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.repetitions.toggle(today - mark * day);
|
|
||||||
|
|
||||||
return habit;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void generateHugeDataSet() throws Throwable
|
|
||||||
{
|
|
||||||
final int nHabits = 30;
|
|
||||||
final int nYears = 5;
|
|
||||||
|
|
||||||
DatabaseHelper.executeAsTransaction(new DatabaseHelper.Command()
|
|
||||||
{
|
|
||||||
@Override
|
|
||||||
public void execute()
|
|
||||||
{
|
|
||||||
Random rand = new Random();
|
|
||||||
|
|
||||||
for(int i = 0; i < nHabits; i++)
|
|
||||||
{
|
|
||||||
Log.i("HabitFixture", String.format("Creating habit %d / %d", i, nHabits));
|
|
||||||
|
|
||||||
Habit habit = new Habit();
|
|
||||||
habit.name = String.format("Habit %d", i);
|
|
||||||
habit.save();
|
|
||||||
|
|
||||||
long today = DateHelper.getStartOfToday();
|
|
||||||
long day = DateHelper.millisecondsInOneDay;
|
|
||||||
|
|
||||||
|
|
||||||
for(int j = 0; j < 365 * nYears; j++)
|
|
||||||
{
|
|
||||||
if(rand.nextBoolean())
|
|
||||||
habit.repetitions.toggle(today - j * day);
|
|
||||||
}
|
|
||||||
|
|
||||||
habit.scores.getTodayValue();
|
|
||||||
habit.streaks.getAll(1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
ExportDBTask task = new ExportDBTask(null);
|
|
||||||
task.setListener(new ExportDBTask.Listener()
|
|
||||||
{
|
|
||||||
@Override
|
|
||||||
public void onExportDBFinished(@Nullable String filename)
|
|
||||||
{
|
|
||||||
if(filename != null)
|
|
||||||
Log.i("HabitFixture", String.format("Huge data set exported to %s", filename));
|
|
||||||
else
|
|
||||||
Log.i("HabitFixture", "Failed to save database");
|
|
||||||
}
|
|
||||||
});
|
|
||||||
task.execute();
|
|
||||||
|
|
||||||
BaseTask.waitForTasks(30000);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void loadHugeDataSet(Context testContext) throws Throwable
|
|
||||||
{
|
|
||||||
File baseDir = DatabaseHelper.getFilesDir("Backups");
|
|
||||||
if(baseDir == null) fail("baseDir should not be null");
|
|
||||||
|
|
||||||
File dst = new File(String.format("%s/%s", baseDir.getPath(), "loopHuge.db"));
|
|
||||||
InputStream in = testContext.getAssets().open("fixtures/loopHuge.db");
|
|
||||||
DatabaseHelper.copy(in, dst);
|
|
||||||
|
|
||||||
ImportDataTask task = new ImportDataTask(dst, null);
|
|
||||||
task.execute();
|
|
||||||
|
|
||||||
BaseTask.waitForTasks(30000);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void purgeHabits()
|
|
||||||
{
|
|
||||||
for(Habit h : Habit.getAll(true))
|
|
||||||
h.cascadeDelete();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,85 +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.unit.commands;
|
|
||||||
|
|
||||||
import android.support.test.runner.AndroidJUnit4;
|
|
||||||
import android.test.suitebuilder.annotation.SmallTest;
|
|
||||||
|
|
||||||
import org.isoron.uhabits.BaseTest;
|
|
||||||
import org.isoron.uhabits.commands.CreateHabitCommand;
|
|
||||||
import org.isoron.uhabits.models.Habit;
|
|
||||||
import org.isoron.uhabits.unit.HabitFixtures;
|
|
||||||
import org.junit.Before;
|
|
||||||
import org.junit.Test;
|
|
||||||
import org.junit.runner.RunWith;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import static junit.framework.Assert.assertTrue;
|
|
||||||
import static org.hamcrest.MatcherAssert.assertThat;
|
|
||||||
import static org.hamcrest.Matchers.equalTo;
|
|
||||||
|
|
||||||
@RunWith(AndroidJUnit4.class)
|
|
||||||
@SmallTest
|
|
||||||
public class CreateHabitCommandTest extends BaseTest
|
|
||||||
{
|
|
||||||
|
|
||||||
private CreateHabitCommand command;
|
|
||||||
private Habit model;
|
|
||||||
|
|
||||||
@Before
|
|
||||||
public void setup()
|
|
||||||
{
|
|
||||||
super.setup();
|
|
||||||
|
|
||||||
model = new Habit();
|
|
||||||
model.name = "New habit";
|
|
||||||
command = new CreateHabitCommand(model);
|
|
||||||
|
|
||||||
HabitFixtures.purgeHabits();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testExecuteUndoRedo()
|
|
||||||
{
|
|
||||||
assertTrue(Habit.getAll(true).isEmpty());
|
|
||||||
|
|
||||||
command.execute();
|
|
||||||
|
|
||||||
List<Habit> allHabits = Habit.getAll(true);
|
|
||||||
assertThat(allHabits.size(), equalTo(1));
|
|
||||||
|
|
||||||
Habit habit = allHabits.get(0);
|
|
||||||
Long id = habit.getId();
|
|
||||||
assertThat(habit.name, equalTo(model.name));
|
|
||||||
|
|
||||||
command.undo();
|
|
||||||
assertTrue(Habit.getAll(true).isEmpty());
|
|
||||||
|
|
||||||
command.execute();
|
|
||||||
allHabits = Habit.getAll(true);
|
|
||||||
assertThat(allHabits.size(), equalTo(1));
|
|
||||||
|
|
||||||
habit = allHabits.get(0);
|
|
||||||
Long newId = habit.getId();
|
|
||||||
assertThat(id, equalTo(newId));
|
|
||||||
assertThat(habit.name, equalTo(model.name));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,85 +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.unit.commands;
|
|
||||||
|
|
||||||
import android.support.test.runner.AndroidJUnit4;
|
|
||||||
import android.test.suitebuilder.annotation.SmallTest;
|
|
||||||
|
|
||||||
import org.isoron.uhabits.BaseTest;
|
|
||||||
import org.isoron.uhabits.commands.DeleteHabitsCommand;
|
|
||||||
import org.isoron.uhabits.models.Habit;
|
|
||||||
import org.isoron.uhabits.unit.HabitFixtures;
|
|
||||||
import org.junit.Before;
|
|
||||||
import org.junit.Rule;
|
|
||||||
import org.junit.Test;
|
|
||||||
import org.junit.rules.ExpectedException;
|
|
||||||
import org.junit.runner.RunWith;
|
|
||||||
|
|
||||||
import java.util.LinkedList;
|
|
||||||
|
|
||||||
import static org.hamcrest.MatcherAssert.assertThat;
|
|
||||||
import static org.hamcrest.Matchers.equalTo;
|
|
||||||
|
|
||||||
@RunWith(AndroidJUnit4.class)
|
|
||||||
@SmallTest
|
|
||||||
public class DeleteHabitsCommandTest extends BaseTest
|
|
||||||
{
|
|
||||||
private DeleteHabitsCommand command;
|
|
||||||
private LinkedList<Habit> habits;
|
|
||||||
|
|
||||||
@Rule
|
|
||||||
public ExpectedException thrown = ExpectedException.none();
|
|
||||||
|
|
||||||
@Before
|
|
||||||
public void setup()
|
|
||||||
{
|
|
||||||
super.setup();
|
|
||||||
|
|
||||||
HabitFixtures.purgeHabits();
|
|
||||||
habits = new LinkedList<>();
|
|
||||||
|
|
||||||
// Habits that shuold be deleted
|
|
||||||
for(int i = 0; i < 3; i ++)
|
|
||||||
{
|
|
||||||
Habit habit = HabitFixtures.createShortHabit();
|
|
||||||
habits.add(habit);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Extra habit that should not be deleted
|
|
||||||
Habit extraHabit = HabitFixtures.createShortHabit();
|
|
||||||
extraHabit.name = "extra";
|
|
||||||
extraHabit.save();
|
|
||||||
|
|
||||||
command = new DeleteHabitsCommand(habits);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testExecuteUndoRedo()
|
|
||||||
{
|
|
||||||
assertThat(Habit.getAll(true).size(), equalTo(4));
|
|
||||||
|
|
||||||
command.execute();
|
|
||||||
assertThat(Habit.getAll(true).size(), equalTo(1));
|
|
||||||
assertThat(Habit.getAll(true).get(0).name, equalTo("extra"));
|
|
||||||
|
|
||||||
thrown.expect(UnsupportedOperationException.class);
|
|
||||||
command.undo();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,120 +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.unit.commands;
|
|
||||||
|
|
||||||
import android.support.test.runner.AndroidJUnit4;
|
|
||||||
import android.test.suitebuilder.annotation.SmallTest;
|
|
||||||
|
|
||||||
import org.isoron.uhabits.BaseTest;
|
|
||||||
import org.isoron.uhabits.commands.EditHabitCommand;
|
|
||||||
import org.isoron.uhabits.models.Habit;
|
|
||||||
import org.isoron.uhabits.unit.HabitFixtures;
|
|
||||||
import org.junit.Before;
|
|
||||||
import org.junit.Test;
|
|
||||||
import org.junit.runner.RunWith;
|
|
||||||
|
|
||||||
import static junit.framework.Assert.assertTrue;
|
|
||||||
import static org.hamcrest.MatcherAssert.assertThat;
|
|
||||||
import static org.hamcrest.Matchers.equalTo;
|
|
||||||
import static org.hamcrest.Matchers.greaterThan;
|
|
||||||
|
|
||||||
@RunWith(AndroidJUnit4.class)
|
|
||||||
@SmallTest
|
|
||||||
public class EditHabitCommandTest extends BaseTest
|
|
||||||
{
|
|
||||||
|
|
||||||
private EditHabitCommand command;
|
|
||||||
private Habit habit;
|
|
||||||
private Habit modified;
|
|
||||||
private Long id;
|
|
||||||
|
|
||||||
@Before
|
|
||||||
public void setup()
|
|
||||||
{
|
|
||||||
super.setup();
|
|
||||||
|
|
||||||
habit = HabitFixtures.createShortHabit();
|
|
||||||
habit.name = "original";
|
|
||||||
habit.freqDen = 1;
|
|
||||||
habit.freqNum = 1;
|
|
||||||
habit.save();
|
|
||||||
|
|
||||||
id = habit.getId();
|
|
||||||
|
|
||||||
modified = new Habit(habit);
|
|
||||||
modified.name = "modified";
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testExecuteUndoRedo()
|
|
||||||
{
|
|
||||||
command = new EditHabitCommand(habit, modified);
|
|
||||||
|
|
||||||
int originalScore = habit.scores.getTodayValue();
|
|
||||||
assertThat(habit.name, equalTo("original"));
|
|
||||||
|
|
||||||
command.execute();
|
|
||||||
refreshHabit();
|
|
||||||
assertThat(habit.name, equalTo("modified"));
|
|
||||||
assertThat(habit.scores.getTodayValue(), equalTo(originalScore));
|
|
||||||
|
|
||||||
command.undo();
|
|
||||||
refreshHabit();
|
|
||||||
assertThat(habit.name, equalTo("original"));
|
|
||||||
assertThat(habit.scores.getTodayValue(), equalTo(originalScore));
|
|
||||||
|
|
||||||
command.execute();
|
|
||||||
refreshHabit();
|
|
||||||
assertThat(habit.name, equalTo("modified"));
|
|
||||||
assertThat(habit.scores.getTodayValue(), equalTo(originalScore));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testExecuteUndoRedo_withModifiedInterval()
|
|
||||||
{
|
|
||||||
modified.freqNum = 1;
|
|
||||||
modified.freqDen = 7;
|
|
||||||
command = new EditHabitCommand(habit, modified);
|
|
||||||
|
|
||||||
int originalScore = habit.scores.getTodayValue();
|
|
||||||
assertThat(habit.name, equalTo("original"));
|
|
||||||
|
|
||||||
command.execute();
|
|
||||||
refreshHabit();
|
|
||||||
assertThat(habit.name, equalTo("modified"));
|
|
||||||
assertThat(habit.scores.getTodayValue(), greaterThan(originalScore));
|
|
||||||
|
|
||||||
command.undo();
|
|
||||||
refreshHabit();
|
|
||||||
assertThat(habit.name, equalTo("original"));
|
|
||||||
assertThat(habit.scores.getTodayValue(), equalTo(originalScore));
|
|
||||||
|
|
||||||
command.execute();
|
|
||||||
refreshHabit();
|
|
||||||
assertThat(habit.name, equalTo("modified"));
|
|
||||||
assertThat(habit.scores.getTodayValue(), greaterThan(originalScore));
|
|
||||||
}
|
|
||||||
|
|
||||||
private void refreshHabit()
|
|
||||||
{
|
|
||||||
habit = Habit.get(id);
|
|
||||||
assertTrue(habit != null);
|
|
||||||
}
|
|
||||||
}
|
|
||||||