Compare commits
685 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 957a5b7c17 | |||
| 64cc9f78a8 | |||
| e50c411d1e | |||
| ce27773138 | |||
| 0864f83307 | |||
| 624cc67d9b | |||
| 462bac8167 | |||
| 5865eb41f7 | |||
| 2bfd4a942d | |||
| b4a33cba39 | |||
| f02c86e61b | |||
| 5021f50e18 | |||
| bf3964a231 | |||
| 657cde75d8 | |||
| c56b86d32c | |||
| 16f20d50a0 | |||
| 7bb88dcb97 | |||
| 7bb62c197f | |||
| 540a618ba8 | |||
| bf24cc608c | |||
| a73459784e | |||
| de3b97dfdf | |||
| 91996924d9 | |||
| 9fe446b424 | |||
| 3857eaf5e9 | |||
| e29fb58922 | |||
| 404fc869b0 | |||
| 001dd5a7c1 | |||
| 7930cc8f31 | |||
| 526830ba61 | |||
| fe1513bb64 | |||
| e06ace9ea8 | |||
| d727dabb2b | |||
| d17e8fcbfb | |||
| be3d7145ab | |||
| cf66587644 | |||
| 0dc9ec2e5f | |||
| 0a375ded96 | |||
| fa5d6f8fee | |||
| 534e6c2d9d | |||
| b6501c9a29 | |||
| 238a1c724d | |||
| 34ca9d17a2 | |||
| e844390614 | |||
| 5e00d07b73 | |||
| 28b6ae7014 | |||
| 2a1bf5fc2e | |||
| ef7483f9dc | |||
| bbb9ed8f99 | |||
| c49d576871 | |||
| bc66ae4f7a | |||
| fa416adbb9 | |||
| 8b835b9918 | |||
| 471c5d341f | |||
| 57296745b3 | |||
| 140ab34a76 | |||
| 0d6ad26505 | |||
| 65cc99dbf7 | |||
| 6855ef9d5e | |||
| 4c58b084c6 | |||
| 5c8e522646 | |||
| 55da0759d4 | |||
| 692fe3218f | |||
| 387930c08d | |||
| 6bd31f9607 | |||
| 9aafe7160c | |||
| 5cc4aac67a | |||
| 831421bc98 | |||
| 161d8f2517 | |||
| bfe4b822b3 | |||
| 19e79a8559 | |||
| 876d4f0ac7 | |||
| f4f7faf3a4 | |||
| 56f2ae57fe | |||
| 3fe09efe9b | |||
| f0de29fbfe | |||
| 324facfffd | |||
| 03e58f9ef2 | |||
| e6c9f7f0c9 | |||
| 42bdedb86a | |||
| ab0c510fda | |||
| e46fd58664 | |||
| 8532bd402e | |||
| 2c599b18ef | |||
| 0d78ba4ba9 | |||
|
|
611dfa00a5 | ||
|
|
54a195243d | ||
|
|
4fc30fae53 | ||
| b3fe9c65d2 | |||
| 09f1ae8765 | |||
| 0a8b763ece | |||
| edd5f25529 | |||
| d81fdb41dc | |||
| 02c8810e46 | |||
| 6adf8061d3 | |||
| d19d57e5df | |||
| fd82e6c24b | |||
| 56263efa39 | |||
| d5eacba303 | |||
| 222261c674 | |||
| b1a06df7f8 | |||
| a1fc7dd0d1 | |||
|
|
10131d5124 | ||
| aa94959ad2 | |||
| 967dc2586b | |||
| 908fd1d6ae | |||
| 45fd8a29e1 | |||
| 4624acd477 | |||
| c8cd4fa389 | |||
| 8c4fab28aa | |||
| d6b91cef01 | |||
| e273fe7375 | |||
| ab3b946c65 | |||
| 38cd47c199 | |||
| fa64bd389d | |||
| d03578fd9e | |||
| 79ae181df2 | |||
| 320dca9070 | |||
| f3b9fc825a | |||
| 50da14022f | |||
| 84a02fe541 | |||
| b3aa3d14c0 | |||
| e9cdfd23c4 | |||
| 659ad2d817 | |||
| d537ba0dfa | |||
| 7c14725d88 | |||
| 638b3f763c | |||
| f876fc50bb | |||
| 919504ccfb | |||
| 1a8d9e72a1 | |||
| 8e82f369c7 | |||
| 0a5677211e | |||
| 65071797c9 | |||
| df1751b21a | |||
| 4e952dd87a | |||
|
|
132dce8919 | ||
| 5c8450191a | |||
| b1d00598eb | |||
| 518ade3165 | |||
| dc5d7930a6 | |||
|
|
ec34043041 | ||
| 4d5407a5cc | |||
| 904489d812 | |||
| d2436a3165 | |||
|
|
bc19858bca | ||
| a998a62cdb | |||
| 1a89bb02be | |||
| 6e8ea471aa | |||
| ec42fb54f4 | |||
| c46fa84135 | |||
| 16dcc0cbc2 | |||
| 6f10039aba | |||
|
|
5cbc0a3292 | ||
| 7f67a9eb63 | |||
| d3f7ebd60c | |||
| 461fe1f0b6 | |||
| 8eb9f398d5 | |||
| f178bcbdd2 | |||
| 66c3136fad | |||
| 4b04966617 | |||
| 3ea21fe823 | |||
| e0df69beb6 | |||
| b5cd4584b2 | |||
| af7c8b1f2e | |||
|
|
283cb2a3f0 | ||
| 79ddbca307 | |||
| 46a0777195 | |||
| b35305e16c | |||
| 8c4a745ecb | |||
|
|
e5162c48ab | ||
| b54c4de5f7 | |||
| 2bdc0b4f5e | |||
| 22db61db01 | |||
| c7cfbd1643 | |||
| 8655437f3e | |||
| 3ad3cf54ec | |||
| 9a470cc61d | |||
| fc2087fe68 | |||
| 7b8ab6a625 | |||
| 2d40fb0b82 | |||
| c961045b63 | |||
| d0db3359fe | |||
| 11378e07bf | |||
| 8132188e46 | |||
| 7eb454788f | |||
| c262adbe85 | |||
| 05aa5b1172 | |||
| dd3d78b82c | |||
| 3d4ae2126b | |||
| 5aa9114aff | |||
| 77e0ad007f | |||
| 2e53b75705 | |||
|
|
0ec03035f5 | ||
|
|
67ae48b527 | ||
|
|
82d2931559 | ||
| a527140802 | |||
| 9ec3d9048a | |||
| 3ed4f3b280 | |||
| f101975320 | |||
| 3a7f27755c | |||
| 3a3be664f7 | |||
| 33ae8d1edf | |||
| cb3b8f2cde | |||
| 307e025b1a | |||
| 03dd24d17b | |||
| 5f4ac21a41 | |||
| b33616d363 | |||
| b7d1c6d254 | |||
| bd30ceee1b | |||
| fe96313162 | |||
| 938fe3325e | |||
| 237de035bb | |||
| ddc85ced0b | |||
| eceb1bfb7d | |||
| 3b737996e9 | |||
| 7f75f9b6da | |||
| 74f78f0fdf | |||
| ef63dd19e7 | |||
| c7878d979f | |||
| ebd294be63 | |||
| 748cec06a8 | |||
| 15a4a2c002 | |||
| 37a9e793e7 | |||
| d54de9df89 | |||
| 94a5db2208 | |||
| a984467516 | |||
| d6dacfd24b | |||
| 3938ae6fa8 | |||
| 7dbbc51a9a | |||
| c9d1bb821c | |||
| 77f406dcee | |||
| 61b0b1fdea | |||
| 8cde0d6aca | |||
| fa9f90a09e | |||
| 28eb615b0e | |||
| c1e10e09a5 | |||
| 35e93fddc6 | |||
| 33596a2797 | |||
| 207f026ceb | |||
| 0f12d02990 | |||
| bc4bbaefac | |||
| a802053ef7 | |||
| cf98d1a5c3 | |||
| cc1e56894b | |||
| 06b5f89b7a | |||
| 17423b3ecd | |||
| 1526f617c5 | |||
| 365eb400d0 | |||
| 785d57c778 | |||
| 8e9f1aa166 | |||
| b2f97cb0a5 | |||
|
|
4c1ff4f0a8 | ||
| 94a48133ec | |||
| 71dd6cde89 | |||
| b33420cabb | |||
| dbe268b8e9 | |||
| 3d53812d7f | |||
| 5b4b436f0f | |||
| 6ef2983906 | |||
| b749f7f391 | |||
| 922b234307 | |||
| 31fdae1c8b | |||
| 5d61fdd3d0 | |||
| 588b45d47b | |||
| 9a059275ce | |||
| 4ae813e6f9 | |||
| 52701666bc | |||
| a90e26691f | |||
| f0c62a5908 | |||
| e899a70eb0 | |||
| aa41717c66 | |||
| 6ba6d7c8c1 | |||
| efd0d1e051 | |||
| a11ad6e909 | |||
| a060cbe578 | |||
| a445ca962b | |||
| 2b6fc06b86 | |||
| 98ad3aab9d | |||
| c7e63a40da | |||
| b6ed33b1e6 | |||
| 91e39372a1 | |||
| c2dd26eeb3 | |||
| 5831340343 | |||
| d7f6f52a49 | |||
| 93b442332d | |||
| e248824bcd | |||
| ec4a381d70 | |||
| b13f2b4228 | |||
| efc7b2cebb | |||
| add08d6054 | |||
| 5d8a348aaf | |||
| ec0e8ac24c | |||
| fee3137a6f | |||
| abe6b10964 | |||
| 6484b96e5a | |||
| 3d3d5b9b96 | |||
| 14364901ff | |||
| 440706882b | |||
| ca9d56e59e | |||
| 9a6dafaa79 | |||
| 9a44774284 | |||
| 2b23b36e36 | |||
| 78d4f86cab | |||
| 18e8390aed | |||
| cabcd5b1bf | |||
| 7e8a2a0c1c | |||
| 650971bf36 | |||
| 00774368d4 | |||
| cbf1bd3e19 | |||
| 4061921b93 | |||
| 59d42fe62f | |||
| 3ffa079e24 | |||
| bb950d61fc | |||
| 0ad0e5cf36 | |||
| 3b56d6d596 | |||
| 8d57273987 | |||
| b98853ab26 | |||
| 071cad73d4 | |||
| 16dc9c25d2 | |||
| 6b23858136 | |||
| e0198e9926 | |||
| 6445bf62bc | |||
| 83ef8564e1 | |||
| 88e8aad0d8 | |||
| a4b6728721 | |||
| ca9745f550 | |||
| 33bc8f78e7 | |||
| 0f223f8504 | |||
| 007996c69e | |||
| ff9d50b32a | |||
| 38024d71ce | |||
| 9ec1afc208 | |||
| e0888a9b4d | |||
| 8aade2f145 | |||
| 1ba1d775f7 | |||
| 605593d739 | |||
| bfbfcbd8cf | |||
| bd6cba8303 | |||
| befc3a0ad8 | |||
| f4c963e2c1 | |||
| e9a4a047c1 | |||
| 7ce1988d2e | |||
| 53911fa410 | |||
| f5f43d9a16 | |||
| dbf569ff87 | |||
| d0e475ad78 | |||
| b3199cf092 | |||
| 73e6f2a2d4 | |||
| 2c80544aaa | |||
| 097a5be864 | |||
| 0287473e61 | |||
| f403dc6f77 | |||
| 23466523df | |||
| 83ca136346 | |||
| 7830b599db | |||
| 49376d4f41 | |||
| 8ee9c9c0b1 | |||
| ee9da29422 | |||
| ae7b0408b2 | |||
| d926d9dbd6 | |||
| 5694da2413 | |||
| 7e0ae144b8 | |||
| 1426d887e7 | |||
| acb8e820fd | |||
| eae0d66f51 | |||
| e933cbbc43 | |||
| 0b95b6a78c | |||
| 5e873a3659 | |||
| d292ecd988 | |||
| 19b484c368 | |||
| 834ae92d87 | |||
| 26ce92d381 | |||
| 0eb12812d4 | |||
| a1a636c718 | |||
| b2811b9797 | |||
| 4db7a6e89c | |||
| 677a643e5b | |||
| dbca3238f6 | |||
| ae5dd700f3 | |||
| 7e4c508d7d | |||
| d0c056eeaa | |||
| f172c69eed | |||
| 0cd4a41438 | |||
| d77c78249c | |||
| d9d48ff984 | |||
| 7be71ba4f8 | |||
| f0534fefbc | |||
| 30ef75bb45 | |||
| 44ed74a693 | |||
| 4aea527e07 | |||
| 638539259a | |||
| 75dec88411 | |||
| 2dc4fcbc46 | |||
| 7977d5247c | |||
| 8b18e32a16 | |||
| dbcad9a5f4 | |||
| 3bba75ff50 | |||
| 9bbeee66e2 | |||
| c6e76f4cfd | |||
| 980db1d171 | |||
| aee5d975db | |||
| e2bb4371d3 | |||
| fcee8552f0 | |||
| a4864e4612 | |||
| 8ddf4574e3 | |||
| f1ca8c5449 | |||
| 81a188f125 | |||
| 44402bf3a4 | |||
| 7f159149ef | |||
| 0c1e8d5131 | |||
| a4e3f7e037 | |||
| b354a0765b | |||
| bbd959dfda | |||
| d05d404c55 | |||
| 8938b0c9a6 | |||
| bd6fcd066c | |||
| 6a5f2abb76 | |||
| 33b5215b00 | |||
| 5d808dd2e8 | |||
| 767ec1b6de | |||
| 9e5f3d8f58 | |||
| 775d028629 | |||
| 4bfb839370 | |||
| 8f64b696d8 | |||
| c4bf31e778 | |||
| c757ce6548 | |||
| 78994bb3c4 | |||
| 2373ba5407 | |||
| b601a643dd | |||
| 90e513e778 | |||
| 728c9557f0 | |||
| 5bd0c842f5 | |||
| 97711087f9 | |||
| 2fe2d8834a | |||
| 93a893d660 | |||
| feff9a18e6 | |||
| b42565b770 | |||
| 3de702ced2 | |||
| 42f7f4042d | |||
| 2115a590f2 | |||
| f5f3ec9f88 | |||
| 6d5a8f5753 | |||
| 06fc04092b | |||
|
|
24c02605d1 | ||
| 11fcb67624 | |||
| abc92e390a | |||
| 52c07660b1 | |||
| 35f778c376 | |||
| 436ae7e574 | |||
| 5c683a77c2 | |||
| dd1f6c9efc | |||
| cba089407b | |||
| a7b0395a2a | |||
| 7d2946360f | |||
| 04e8432522 | |||
| 13d34945b4 | |||
| 756578508e | |||
| 38fc7650b9 | |||
| cf06ec0a4b | |||
| f0701f7b35 | |||
| de8018af7d | |||
| ac885e1503 | |||
| f85e09288c | |||
| 6f11596bb7 | |||
| 64c4367706 | |||
| c08702341a | |||
| abb8c09bc9 | |||
| 87255ceb25 | |||
| aedbfded0f | |||
| 779c0040bd | |||
| 7bba6a887f | |||
| 52a1d19793 | |||
| 35e346e7ea | |||
| 3102158bdb | |||
| 7afa65a53c | |||
| 2e5533d480 | |||
| b29c7e695a | |||
| 7df745eb82 | |||
| c0d518ca4d | |||
| eeff14a2ca | |||
| af3b18f518 | |||
| 3811f4b339 | |||
| 50a8aece6f | |||
| 2f66cfc417 | |||
| 132ce36a57 | |||
| 147f010d1b | |||
| afc91ed89a | |||
| 684c37d167 | |||
| 8b296ce2ae | |||
| e2e9e2e27a | |||
| 8b2f31c44a | |||
| 83db9fe2f2 | |||
| 9891139b5a | |||
| cbc8cbfea3 | |||
| 96c46b655d | |||
| 0de52d4fa3 | |||
| 16d85dc4c7 | |||
| c51b1fd399 | |||
| eb8dd1d450 | |||
| 357646152f | |||
| ae5be202b2 | |||
| cc3e2153d0 | |||
| 7433a2413d | |||
| 1cd8eb6849 | |||
| 7f009e2365 | |||
| 4cec7d7367 | |||
| f59c0bd7ff | |||
| 2d2bb8b4ed | |||
| e476096ae1 | |||
| e2c814a982 | |||
| 4fcaa68baf | |||
| 02e45dbe27 | |||
| bf6562f854 | |||
| 3c927e009a | |||
| a9bcae0f2f | |||
| bc54f3f916 | |||
| 5763d76167 | |||
| 86b66b1388 | |||
| 5e0422848b | |||
| a67a3297b1 | |||
| b2f2d4ad28 | |||
| 4dc8201dcb | |||
| f24e300b40 | |||
| 21157eaa19 | |||
| 0ea2c8e5c8 | |||
| 826491bc90 | |||
| 72f5ca5531 | |||
| f9da90a93a | |||
| 96c6a97ad0 | |||
| 20469789ea | |||
| abafffcff1 | |||
| d45a4445cc | |||
| 94f56a8869 | |||
| bc331d0a4d | |||
| 2ba7246e5f | |||
| 67b88c5012 | |||
| e0b637e84d | |||
| e14d73cf32 | |||
| 16b9584868 | |||
| c091116105 | |||
| 37e1a6233c | |||
| 6838a0f2d3 | |||
| 53e737c169 | |||
| 285f79ed95 | |||
| 4f65c8bef1 | |||
| 51b7cfc8fa | |||
| 55ed2585ea | |||
| 2c62e1578a | |||
| e3d96c0431 | |||
| b4c2d2237a | |||
| d14fbbd130 | |||
| e2c99d745e | |||
| dfe41176bc | |||
| 1ef4f8d456 | |||
| 6c810ee7a3 | |||
| 5115379fdd | |||
| d176ea91fb | |||
| 62df660079 | |||
| 790beb185a | |||
| 59c0af17d7 | |||
| 28dad560a6 | |||
| 9e410f8395 | |||
| 3656c51e95 | |||
| d3ebb4ff25 | |||
| 3c595bc79d | |||
| 1120f56dd4 | |||
| 2dfbcfcdb0 | |||
| 90a3964f0f | |||
| 6c05366f0f | |||
| dcc771abe7 | |||
| 743431ef67 | |||
| d5fc1a6886 | |||
| eeb0b109ae | |||
| ad391fa791 | |||
| e8bbae8ef9 | |||
| c9793df7c7 | |||
| 3c6114fc87 | |||
| 4ea4201b6a | |||
|
|
30b5b90091 | ||
| e6b7b8b590 | |||
| 2d675ed9b0 | |||
| 1db2f69f05 | |||
| 49a80faca3 | |||
| aa5df56437 | |||
| 581197be03 | |||
| dfe5c4954e | |||
| a0582b65d5 | |||
| 9edc3e12c9 | |||
| 7bb3db213f | |||
| e05a69b527 | |||
| d5df6ddcdb | |||
| 3016263750 | |||
| f9377e1768 | |||
| ae0dad9120 | |||
| be114bde7f | |||
| e7148abc2e | |||
| 2d87076a48 | |||
| 7da4ddf91b | |||
| e4e8d77acc | |||
| 7945a5faf9 | |||
| 3f7d25461d | |||
| 519737a1c3 | |||
| c3ff1fbe03 | |||
| d39e1978a2 | |||
| 536c095f23 | |||
| 8aaa5aca28 | |||
| 5540a66e08 | |||
| 01ffc6c144 | |||
| 21aa658acc | |||
| e17667d85d | |||
| f2948dac6f | |||
| 31a7d92f77 | |||
| 82d7970f86 | |||
| af1a21a959 | |||
| e7c1575083 | |||
| d5a14ca55b | |||
| c4d6b80944 | |||
| c4b6cad6bb | |||
| 7070530d0e | |||
| 1332a70eb4 | |||
| 11c9a3dab0 | |||
| 74f7b0fd28 | |||
| e693504183 | |||
| 7d9a94ae9e | |||
| 326cb8f73f | |||
| 6826bd1ddc | |||
| b5bc347624 | |||
| 55c058ff42 | |||
| e829bb8109 | |||
| 0921f9346e | |||
| eb017bf99b | |||
| 79b6ef8200 | |||
| 7ba62d6784 | |||
| f5e4a88415 | |||
| 075b7812eb | |||
| 3d42505fb9 | |||
| 824f98dd96 | |||
| fcb82bcb72 | |||
| 851cae3662 | |||
| 7778c5fb21 | |||
| ef847dac17 | |||
| 8102c18c67 | |||
| 59ed9ec9bd | |||
| ffdc923268 | |||
| 9232378d04 | |||
| b20fd44cbc | |||
| ded8800017 | |||
| 606f66b8d9 | |||
| 1bb6cd405b | |||
| babf7d64f0 | |||
| dfbcf78dd7 | |||
| e01c668e4d | |||
| 2eef696027 | |||
| ddd10cacd1 | |||
| 0cdde4901e | |||
| f13e9b7362 | |||
| 558f72d7c5 | |||
| 6e493f55bc | |||
| 5186ab840a | |||
| 65fd82d888 | |||
| 866b62987c | |||
| 18abb2038f | |||
| f7f4b5eeb0 | |||
| 45a7433773 | |||
| 40420c3a77 | |||
| 988b39f2e5 | |||
| a0803966f9 | |||
| e4af662836 | |||
| e95adab422 | |||
| 012fed01eb | |||
| 4cf2b8072b | |||
| 196a79a88c | |||
| 4b7e2e79a7 | |||
| 9156bba267 | |||
| 1a18bb939d | |||
| 144524e53b | |||
| 3d1c53396c | |||
| 1930db3cd1 | |||
| a2c2a5531a | |||
| eee2605f74 | |||
|
|
9df0c9ae9e | ||
| e0533505c1 | |||
|
|
433894336c | ||
| 9061182301 | |||
| 8c45f52d56 |
52
.gitignore
vendored
@@ -1,35 +1,25 @@
|
||||
#built application files
|
||||
*.apk
|
||||
*.ap_
|
||||
|
||||
# files for the dex VM
|
||||
*.dex
|
||||
|
||||
# Java class files
|
||||
*.apk
|
||||
*.class
|
||||
|
||||
# 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/
|
||||
*.dex
|
||||
*.iml
|
||||
|
||||
*.local.*
|
||||
*.swp
|
||||
*.trace
|
||||
*~
|
||||
.DS_Store
|
||||
.classpath
|
||||
.gradle
|
||||
.idea
|
||||
.project
|
||||
Thumbs.db
|
||||
art/
|
||||
bin/
|
||||
build/
|
||||
captures/
|
||||
docs/
|
||||
gen/
|
||||
local.properties
|
||||
crowdin.yaml
|
||||
local
|
||||
secret/
|
||||
|
||||
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
|
||||
156
CHANGELOG.md
@@ -1,10 +1,164 @@
|
||||
# Changelog
|
||||
|
||||
### 1.7.11 (Aug 10, 2019)
|
||||
|
||||
* Fix bug that produced corrupted CSV files in some countries
|
||||
|
||||
### 1.7.10 (June 15, 2019)
|
||||
|
||||
* Fix bug that prevented some devices from showing notifications.
|
||||
* Update targetSdk to Android Pie (API level 28)
|
||||
|
||||
### 1.7.8 (April 21, 2018)
|
||||
|
||||
* Add support for adaptive icons (Oreo)
|
||||
* Add support for notification channels (Oreo)
|
||||
* Update translations
|
||||
|
||||
### 1.7.7 (September 30, 2017)
|
||||
|
||||
* Fix bug that caused reminders to show repeatedly on DST changes
|
||||
|
||||
### 1.7.6 (July 18, 2017)
|
||||
|
||||
* Fix bug that caused widgets not to render sometimes
|
||||
* Fix other minor bugs
|
||||
* Update translations
|
||||
|
||||
### 1.7.3 (May 30, 2017)
|
||||
|
||||
* Improve performance of 'sort by score'
|
||||
* Other minor bug fixes
|
||||
|
||||
### 1.7.2 (May 27, 2017)
|
||||
|
||||
* Fix crash at startup
|
||||
|
||||
### 1.7.1 (May 21, 2017)
|
||||
|
||||
* Fix crash (BadParcelableException)
|
||||
* Fix layout for RTL languages such as Arabic
|
||||
* Automatically detect and reject invalid database files
|
||||
* Add Hebrew translation
|
||||
|
||||
### 1.7.0 (Mar 31, 2017)
|
||||
|
||||
* Sort habits automatically
|
||||
* Allow swiping the header to see previous days
|
||||
* Import backups directly from Google Drive or Dropbox
|
||||
* Refresh data automatically at midnight
|
||||
* Other minor bug fixes and enhancements
|
||||
|
||||
### 1.6.2 (Oct 13, 2016)
|
||||
|
||||
* Fix crash on Android 4.1
|
||||
|
||||
### 1.6.1 (Oct 10, 2016)
|
||||
|
||||
* Fix a crash at startup when database is corrupted
|
||||
|
||||
### 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)
|
||||
|
||||
* Fix crash upon opening settings screen in some phones
|
||||
* Fix missing folders in CSV archive
|
||||
* Add Serbian translation
|
||||
|
||||
### 1.5.3 (May 22, 2016)
|
||||
|
||||
* Complete Arabic and Czech translations
|
||||
* Fix crash at startup
|
||||
* Fix checkmark widget on custom launchers
|
||||
|
||||
### 1.5.2 (May 19, 2016)
|
||||
|
||||
* Fix missing attachment on bug reports
|
||||
* Fix bug that prevents some widgets from rendering
|
||||
* Complete Japanese translation
|
||||
|
||||
### 1.5.1 (May 17, 2016)
|
||||
|
||||
* Fix build on F-Droid
|
||||
|
||||
### 1.5.0 (May 15, 2016)
|
||||
|
||||
* Add night mode, with AMOLED support
|
||||
* Backport material design to older devices
|
||||
* Display more information on statistics screen
|
||||
* Display score on main screen and checkmark widget
|
||||
* Make widgets react immediately to touch
|
||||
* Reschedule reminders after reboot
|
||||
* Pick first day of the week according to country
|
||||
* Add option to reverse order of days on main screen
|
||||
* Add option to change notification sounds
|
||||
* Add Catalan, Indonesian, Turkish, Ukrainian translations
|
||||
* Switch between Simplified/Traditional Chinese according to country
|
||||
|
||||
### 1.4.1 (April 9, 2016)
|
||||
|
||||
* Show error message on widgets, instead of crashing
|
||||
* Complete French translation
|
||||
* Minor fixes to other translations
|
||||
|
||||
### 1.4.0 (April 7, 2016)
|
||||
|
||||
* Ability to import data from third-party apps
|
||||
* Ability to save and restore full database backup
|
||||
* Show more information on streak chart
|
||||
* Simplify interface for creating habits
|
||||
* Add link to Frequently Asked Questions (FAQ)
|
||||
* Reduce app loading time and lag on widgets
|
||||
* Generate bug reports on crash and from settings screen
|
||||
* Disable vibration according to phone settings
|
||||
* Add Czech translation
|
||||
* Fix wrong month names for some languages
|
||||
|
||||
### 1.3.3 (March 20, 2016)
|
||||
|
||||
* Add Spanish and Korean translations
|
||||
* Make small corrections to other translations
|
||||
* Fix incorrect date in history calendar
|
||||
|
||||
### 1.3.2 (March 18, 2016)
|
||||
|
||||
* Add Arabic, Italian, Polish, Russian and Swedish translations
|
||||
* Minor fixes to German and French translations
|
||||
* Minor bug fixes
|
||||
|
||||
### 1.3.1 (March 15, 2016)
|
||||
|
||||
* Fixes crash on devices with large screen, such as the Nexus 10
|
||||
* Fixes crash when clicking widgets and reminders of deleted habits
|
||||
* Other minor bug fixes
|
||||
|
||||
### 1.3.0 (March 12, 2016)
|
||||
|
||||
* New frequency plot: view total repetitions per day of week
|
||||
* New history editor: put checkmarks in the past
|
||||
* German, French and Japanese translations
|
||||
* Add German, French and Japanese translations
|
||||
* Add about screen, with credits to all contributors
|
||||
* Fix small bug that prevented habit from being reordered
|
||||
* Fix small bug caused by rotating the device
|
||||
|
||||
160
NOTICE.md
@@ -59,28 +59,6 @@ under the SIL OFL 1.1.
|
||||
requirement for fonts to remain under this license does not apply
|
||||
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
|
||||
|
||||
<https://github.com/google/material-design-icons>
|
||||
@@ -89,3 +67,141 @@ Material design icons are the official icon set from Google that are designed
|
||||
under the material design guidelines. Available under the Creative Common
|
||||
Attribution 4.0 International License (CC-BY 4.0).
|
||||
|
||||
### Android Flow Layout
|
||||
|
||||
<https://github.com/ApmeM/android-flowlayout>
|
||||
|
||||
Extended linear layout that wrap its content when there is no place in the current line.
|
||||
|
||||
Copyright 2011, Artem Votincev (apmem.org)
|
||||
|
||||
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.
|
||||
|
||||
### 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.
|
||||
|
||||
67
README.md
@@ -1,12 +1,32 @@
|
||||
# Loop Habit Tracker
|
||||
|
||||
<a href="https://circleci.com/gh/iSoron/uhabits/tree/dev">
|
||||
<img src="https://img.shields.io/circleci/project/iSoron/uhabits/dev.svg">
|
||||
</a>
|
||||
<!--
|
||||
<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" />
|
||||
</a>
|
||||
-->
|
||||
|
||||
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
|
||||
show you how your habits improved over time. It is completely ad-free and open
|
||||
source.
|
||||
|
||||
<p align="center">
|
||||
<a href="https://play.google.com/store/apps/details?id=org.isoron.uhabits&utm_source=global_co&utm_medium=prtnr&utm_content=Mar2515&utm_campaign=PartBadge&pcampaignid=MKT-AC-global-none-all-co-pr-py-PartBadges-Oct1515-1"><img alt="Get it on Google Play" src="https://play.google.com/intl/en_us/badges/images/apps/en-play-badge-border.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>
|
||||
|
||||
## 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
|
||||
|
||||
@@ -39,20 +59,12 @@ source.
|
||||
and there will never be. The complete source code is available under the
|
||||
GPLv3.
|
||||
|
||||
## Screenshots
|
||||
|
||||
[![Main screen][screen1th]][screen1]
|
||||
[![Edit habit][screen2th]][screen2]
|
||||
[![Habit strength][screen3th]][screen3]
|
||||
[![Habit history and streaks][screen4th]][screen4]
|
||||
[![Widgets][screen5th]][screen5]
|
||||
|
||||
## Installing
|
||||
|
||||
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];
|
||||
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
|
||||
|
||||
@@ -63,43 +75,56 @@ contribute, even if you are not a software developer.
|
||||
* **Report bugs, suggest features.** The easiest way to contribute is to simply
|
||||
use the app and let us know if you find any problems or have any suggestions
|
||||
to improve it. You can either use the link inside the app, or open an issue
|
||||
at GitHub.
|
||||
at GitHub. If you would like to receive the newest versions of the app
|
||||
earlier than everyone else, [join our open beta on Google Play][beta].
|
||||
|
||||
* **Spread the word.** If you like the app, share it with your family, friends
|
||||
and colleagues. You can also rate and review the app on Google Play Store, to help
|
||||
other users find it more easily.
|
||||
|
||||
* **Translate the app into your own language.** If you are not a native English
|
||||
speaker, and would like to see the app translated into your own language,
|
||||
please join our [open translation project at POEditor][poedit].
|
||||
please join our [open translation project at POEditor][poedit]. If the translation
|
||||
is already completed, you are also very welcome to join and proofread it.
|
||||
|
||||
* **Write some code.** If you are an Android developer, you are very welcome to
|
||||
contribute with code. Please, see the [developer guidelines][dev-guide] for more details.
|
||||
|
||||
## License
|
||||
|
||||
This program 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.
|
||||
<img align="right" src="https://www.gnu.org/graphics/gplv3-88x31.png">
|
||||
|
||||
This program 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.
|
||||
Copyright (C) 2016 Álinson Santos Xavier <isoron@gmail.com>
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
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/>.
|
||||
|
||||
[screen1]: screenshots/original/uhabits1.png
|
||||
[screen2]: screenshots/original/uhabits2.png
|
||||
[screen3]: screenshots/original/uhabits3.png
|
||||
[screen4]: screenshots/original/uhabits4.png
|
||||
[screen5]: screenshots/original/uhabits5.png
|
||||
[screen6]: screenshots/original/uhabits6.png
|
||||
[screen1th]: screenshots/thumbs/uhabits1.png
|
||||
[screen2th]: screenshots/thumbs/uhabits2.png
|
||||
[screen3th]: screenshots/thumbs/uhabits3.png
|
||||
[screen4th]: screenshots/thumbs/uhabits4.png
|
||||
[screen5th]: screenshots/thumbs/uhabits5.png
|
||||
[screen6th]: screenshots/thumbs/uhabits6.png
|
||||
[poedit]: https://poeditor.com/join/project/8DWX5pfjS0
|
||||
[playstore]: https://play.google.com/store/apps/details?id=org.isoron.uhabits
|
||||
[releases]: https://github.com/iSoron/uhabits/releases
|
||||
[fdroid]: http://f-droid.org/app/org.isoron.uhabits
|
||||
[dev-guide]: https://github.com/iSoron/uhabits/wiki/Developer-guidelines
|
||||
[build]: https://github.com/iSoron/uhabits/wiki/Developer-guidelines#building
|
||||
[beta]: https://play.google.com/apps/testing/org.isoron.uhabits
|
||||
|
||||
149
app/build.gradle
@@ -1,42 +1,165 @@
|
||||
apply plugin: 'com.android.application'
|
||||
apply plugin: 'com.neenbedankt.android-apt'
|
||||
apply plugin: 'me.tatarka.retrolambda'
|
||||
apply plugin: 'jacoco'
|
||||
apply plugin: 'com.github.triplet.play'
|
||||
|
||||
android {
|
||||
compileSdkVersion 23
|
||||
buildToolsVersion "21.1.2"
|
||||
compileSdkVersion 28
|
||||
buildToolsVersion "28.0.3"
|
||||
|
||||
// signingConfigs {
|
||||
// release {
|
||||
// storeFile file(LOOP_STORE_FILE)
|
||||
// storePassword LOOP_STORE_PASSWORD
|
||||
// keyAlias LOOP_KEY_ALIAS
|
||||
// keyPassword LOOP_KEY_PASSWORD
|
||||
// }
|
||||
// }
|
||||
|
||||
playAccountConfigs {
|
||||
defaultAccountConfig {
|
||||
jsonFile = file('../secret/playstore.json')
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
defaultConfig {
|
||||
applicationId "org.isoron.uhabits"
|
||||
minSdkVersion 15
|
||||
targetSdkVersion 23
|
||||
targetSdkVersion 28
|
||||
|
||||
buildConfigField "Integer", "databaseVersion", "15"
|
||||
buildConfigField "String", "databaseFilename", "\"uhabits.db\""
|
||||
|
||||
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
|
||||
testInstrumentationRunnerArgument "size", "medium"
|
||||
|
||||
// playAccountConfig = playAccountConfigs.defaultAccountConfig
|
||||
}
|
||||
|
||||
buildTypes {
|
||||
release {
|
||||
minifyEnabled false
|
||||
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt'
|
||||
// signingConfig signingConfigs.release
|
||||
}
|
||||
debug {
|
||||
testCoverageEnabled = true
|
||||
testCoverageEnabled = false
|
||||
}
|
||||
}
|
||||
|
||||
lintOptions {
|
||||
checkReleaseBuilds false
|
||||
}
|
||||
|
||||
compileOptions {
|
||||
targetCompatibility 1.8
|
||||
sourceCompatibility 1.8
|
||||
}
|
||||
|
||||
testOptions {
|
||||
unitTests.all {
|
||||
testLogging {
|
||||
events "passed", "skipped", "failed", "standardOut", "standardError"
|
||||
outputs.upToDateWhen { false }
|
||||
showStandardStreams = true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
compile 'com.android.support:support-v4:23.1.1'
|
||||
compile 'com.github.paolorotolo:appintro:3.4.0'
|
||||
compile project(':libs:drag-sort-listview:library')
|
||||
compile files('libs/ActiveAndroid.jar')
|
||||
|
||||
androidTestCompile 'com.android.support:support-annotations:23.1.1'
|
||||
androidTestCompile 'com.android.support.test:runner:0.4.1'
|
||||
androidTestCompile 'com.android.support.test:rules:0.4.1'
|
||||
androidTestCompile 'com.android.support.test.espresso:espresso-core:2.2.1'
|
||||
androidTestCompile 'com.android.support.test.espresso:espresso-intents:2.2.1'
|
||||
androidTestApt 'com.google.dagger:dagger-compiler:2.2'
|
||||
|
||||
androidTestCompile 'com.android.support:support-annotations:27.1.1'
|
||||
androidTestCompile 'com.android.support.test:rules:0.5'
|
||||
androidTestCompile 'com.android.support.test:runner:0.5'
|
||||
androidTestCompile 'com.google.auto.factory:auto-factory:1.0-beta3'
|
||||
androidTestCompile "com.google.dexmaker:dexmaker:1.2"
|
||||
androidTestCompile 'com.google.dexmaker:dexmaker-mockito:1.2'
|
||||
androidTestCompile 'org.mockito:mockito-core:1.10.19'
|
||||
|
||||
apt 'com.google.dagger:dagger-compiler:2.2'
|
||||
apt 'com.jakewharton:butterknife-compiler:8.0.1'
|
||||
|
||||
compile 'com.android.support:appcompat-v7:27.1.1'
|
||||
compile 'com.android.support:design:27.1.1'
|
||||
compile 'com.android.support:preference-v14:27.1.1'
|
||||
compile 'com.android.support:support-v4:27.1.1'
|
||||
compile 'com.getpebble:pebblekit:3.0.0'
|
||||
compile 'com.github.paolorotolo:appintro:3.4.0'
|
||||
compile 'com.google.auto.factory:auto-factory:1.0-beta3'
|
||||
compile 'com.google.dagger:dagger:2.2'
|
||||
compile 'com.jakewharton:butterknife:8.0.1'
|
||||
compile 'com.opencsv:opencsv:3.7'
|
||||
compile 'org.apmem.tools:layouts:1.10@aar'
|
||||
compile 'org.jetbrains:annotations-java5:15.0'
|
||||
|
||||
provided 'javax.annotation:jsr250-api:1.0'
|
||||
|
||||
testApt 'com.google.dagger:dagger-compiler:2.2'
|
||||
|
||||
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') {
|
||||
exclude group: 'com.android.support'
|
||||
}
|
||||
|
||||
androidTestCompile('com.android.support.test.espresso:espresso-intents:2.2.1') {
|
||||
exclude group: 'com.android.support'
|
||||
}
|
||||
|
||||
androidTestCompile('com.android.support.test.espresso:espresso-contrib:2.2.1') {
|
||||
exclude group: 'com.android.support'
|
||||
}
|
||||
}
|
||||
|
||||
retrolambda {
|
||||
defaultMethods true
|
||||
}
|
||||
|
||||
jacoco {
|
||||
toolVersion = "0.7.4.201502262128"
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
//play {
|
||||
// track = 'alpha'
|
||||
//}
|
||||
|
||||
3
app/proguard-rules.txt
Normal file
@@ -0,0 +1,3 @@
|
||||
-dontwarn java.beans.**
|
||||
-dontwarn java.lang.**
|
||||
-dontobfuscate
|
||||
19
app/src/androidTest/assets/habitbull.csv
Normal file
@@ -0,0 +1,19 @@
|
||||
HabitName,HabitDescription,HabitCategory,CalendarDate,Value,CommentText
|
||||
Breed dragons,with love and fire,Diet & Food,2016-03-18,1,
|
||||
Breed dragons,with love and fire,Diet & Food,2016-03-19,1,
|
||||
Breed dragons,with love and fire,Diet & Food,2016-03-21,1,
|
||||
Reduce sleep,only 2 hours per day,Time Management,2016-03-15,1,
|
||||
Reduce sleep,only 2 hours per day,Time Management,2016-03-16,1,
|
||||
Reduce sleep,only 2 hours per day,Time Management,2016-03-17,1,
|
||||
Reduce sleep,only 2 hours per day,Time Management,2016-03-21,1,
|
||||
No-arms pushup,Become like water my friend!,Fitness,2016-03-15,1,
|
||||
No-arms pushup,Become like water my friend!,Fitness,2016-03-16,1,
|
||||
No-arms pushup,Become like water my friend!,Fitness,2016-03-18,1,
|
||||
No-arms pushup,Become like water my friend!,Fitness,2016-03-21,1,
|
||||
No-arms pushup,Become like water my friend!,Fitness,2016-03-15,1,
|
||||
No-arms pushup,Become like water my friend!,Fitness,2016-03-16,1,
|
||||
No-arms pushup,Become like water my friend!,Fitness,2016-03-18,1,
|
||||
No-arms pushup,Become like water my friend!,Fitness,2016-03-21,1,
|
||||
Grow spiritually,"transcend ego, practice compassion, smile and breath",Meditation,2016-03-15,1,
|
||||
Grow spiritually,"transcend ego, practice compassion, smile and breath",Meditation,2016-03-17,1,
|
||||
Grow spiritually,"transcend ego, practice compassion, smile and breath",Meditation,2016-03-21,1,
|
||||
|
BIN
app/src/androidTest/assets/icon.png
Normal file
|
After Width: | Height: | Size: 48 KiB |
BIN
app/src/androidTest/assets/loop.db
Normal file
5
app/src/androidTest/assets/pull_failed
Executable file
@@ -0,0 +1,5 @@
|
||||
#!/bin/bash
|
||||
P=/sdcard/Android/data/org.isoron.uhabits/cache/Failed/
|
||||
|
||||
adb pull $P Failed/
|
||||
adb shell rm -r $P
|
||||
BIN
app/src/androidTest/assets/rewire.db
Normal file
BIN
app/src/androidTest/assets/tickmate.db
Normal file
|
After Width: | Height: | Size: 8.3 KiB |
|
After Width: | Height: | Size: 6.3 KiB |
|
After Width: | Height: | Size: 15 KiB |
|
After Width: | Height: | Size: 8.3 KiB |
BIN
app/src/androidTest/assets/views/common/HistoryChart/render.png
Normal file
|
After Width: | Height: | Size: 58 KiB |
|
After Width: | Height: | Size: 54 KiB |
|
After Width: | Height: | Size: 31 KiB |
|
After Width: | Height: | Size: 53 KiB |
BIN
app/src/androidTest/assets/views/common/RingView/render.png
Normal file
|
After Width: | Height: | Size: 8.2 KiB |
|
After Width: | Height: | Size: 15 KiB |
BIN
app/src/androidTest/assets/views/common/ScoreChart/render.png
Normal file
|
After Width: | Height: | Size: 25 KiB |
|
After Width: | Height: | Size: 27 KiB |
|
After Width: | Height: | Size: 19 KiB |
|
After Width: | Height: | Size: 25 KiB |
|
After Width: | Height: | Size: 21 KiB |
|
After Width: | Height: | Size: 19 KiB |
BIN
app/src/androidTest/assets/views/common/StreakChart/render.png
Normal file
|
After Width: | Height: | Size: 16 KiB |
|
After Width: | Height: | Size: 2.5 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
|
||||
{
|
||||
|
||||
|
||||
}
|
||||
172
app/src/androidTest/java/org/isoron/uhabits/BaseAndroidTest.java
Normal file
@@ -0,0 +1,172 @@
|
||||
/*
|
||||
* 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 android.util.*;
|
||||
|
||||
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.io.*;
|
||||
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;
|
||||
|
||||
protected ModelFactory modelFactory;
|
||||
|
||||
private boolean isDone = false;
|
||||
|
||||
@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 = 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 runConcurrently(Runnable... runnableList) throws Exception
|
||||
{
|
||||
isDone = false;
|
||||
ExecutorService executor = Executors.newFixedThreadPool(100);
|
||||
List<Future> futures = new LinkedList<>();
|
||||
for (Runnable r : runnableList)
|
||||
futures.add(executor.submit(() ->
|
||||
{
|
||||
while (!isDone) r.run();
|
||||
return null;
|
||||
}));
|
||||
|
||||
Thread.sleep(3000);
|
||||
isDone = true;
|
||||
executor.shutdown();
|
||||
for(Future f : futures) f.get();
|
||||
while (!executor.isTerminated()) Thread.sleep(50);
|
||||
}
|
||||
|
||||
protected void setTheme(@StyleRes int themeId)
|
||||
{
|
||||
targetContext.setTheme(themeId);
|
||||
StyledResources.setFixedTheme(themeId);
|
||||
}
|
||||
|
||||
protected void sleep(int time)
|
||||
{
|
||||
try
|
||||
{
|
||||
Thread.sleep(time);
|
||||
}
|
||||
catch (InterruptedException e)
|
||||
{
|
||||
fail();
|
||||
}
|
||||
}
|
||||
|
||||
protected void startTracing()
|
||||
{
|
||||
File dir = FileUtils.getFilesDir(targetContext, "Profile");
|
||||
assertNotNull(dir);
|
||||
String tracePath = dir.getAbsolutePath() + "/performance.trace";
|
||||
Log.d("PerformanceTest", String.format("Saving trace file to %s", tracePath));
|
||||
Debug.startMethodTracingSampling(tracePath, 0, 1000);
|
||||
}
|
||||
|
||||
protected void stopTracing()
|
||||
{
|
||||
Debug.stopMethodTracing();
|
||||
}
|
||||
}
|
||||
246
app/src/androidTest/java/org/isoron/uhabits/BaseViewTest.java
Normal file
@@ -0,0 +1,246 @@
|
||||
/*
|
||||
* Copyright (C) 2016 Álinson Santos Xavier <isoron@gmail.com>
|
||||
*
|
||||
* This file is part of Loop Habit Tracker.
|
||||
*
|
||||
* Loop Habit Tracker is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation, either version 3 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* Loop Habit Tracker is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.isoron.uhabits;
|
||||
|
||||
import android.graphics.*;
|
||||
import android.os.*;
|
||||
import android.support.annotation.*;
|
||||
import android.view.*;
|
||||
import android.widget.*;
|
||||
|
||||
import org.isoron.uhabits.utils.*;
|
||||
import org.isoron.uhabits.widgets.*;
|
||||
|
||||
import java.io.*;
|
||||
|
||||
import static android.view.View.MeasureSpec.*;
|
||||
import static junit.framework.Assert.*;
|
||||
|
||||
public class BaseViewTest extends BaseAndroidTest
|
||||
{
|
||||
protected static final double DEFAULT_SIMILARITY_CUTOFF = 0.09;
|
||||
|
||||
public static final int HISTOGRAM_BIN_SIZE = 8;
|
||||
|
||||
private double similarityCutoff;
|
||||
|
||||
@Override
|
||||
public void setUp()
|
||||
{
|
||||
super.setUp();
|
||||
similarityCutoff = DEFAULT_SIMILARITY_CUTOFF;
|
||||
}
|
||||
|
||||
protected void assertRenders(View view, String expectedImagePath)
|
||||
throws IOException
|
||||
{
|
||||
StringBuilder errorMessage = new StringBuilder();
|
||||
expectedImagePath = getVersionedViewAssetPath(expectedImagePath);
|
||||
|
||||
if (view.isLayoutRequested()) measureView(view, view.getMeasuredWidth(),
|
||||
view.getMeasuredHeight());
|
||||
|
||||
view.setDrawingCacheEnabled(true);
|
||||
view.buildDrawingCache();
|
||||
Bitmap actual = view.getDrawingCache();
|
||||
Bitmap expected = getBitmapFromAssets(expectedImagePath);
|
||||
|
||||
int width = actual.getWidth();
|
||||
int height = actual.getHeight();
|
||||
Bitmap scaledExpected =
|
||||
Bitmap.createScaledBitmap(expected, width, height, true);
|
||||
|
||||
double distance;
|
||||
boolean similarEnough = true;
|
||||
|
||||
if ((distance = compareHistograms(getHistogram(actual),
|
||||
getHistogram(scaledExpected))) > similarityCutoff)
|
||||
{
|
||||
similarEnough = false;
|
||||
errorMessage.append(String.format(
|
||||
"Rendered image has wrong histogram (distance=%f). ",
|
||||
distance));
|
||||
}
|
||||
|
||||
if (!similarEnough)
|
||||
{
|
||||
saveBitmap(expectedImagePath, ".expected", scaledExpected);
|
||||
String path = saveBitmap(expectedImagePath, "", actual);
|
||||
errorMessage.append(
|
||||
String.format("Actual rendered image saved to %s", path));
|
||||
fail(errorMessage.toString());
|
||||
}
|
||||
|
||||
expected.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
|
||||
{
|
||||
InputStream stream = testContext.getAssets().open(path);
|
||||
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)
|
||||
{
|
||||
String result = null;
|
||||
|
||||
if (android.os.Build.VERSION.SDK_INT >= 21)
|
||||
{
|
||||
try
|
||||
{
|
||||
String vpath = "views-v21/" + path;
|
||||
testContext.getAssets().open(vpath);
|
||||
result = vpath;
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
}
|
||||
|
||||
if (result == null) result = "views/" + path;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private String saveBitmap(String filename, String suffix, Bitmap bitmap)
|
||||
throws IOException
|
||||
{
|
||||
File dir = FileUtils.getSDCardDir("test-screenshots");
|
||||
if (dir == null) dir = FileUtils.getFilesDir(targetContext,"test-screenshots");
|
||||
if (dir == null) throw new RuntimeException(
|
||||
"Could not find suitable dir for screenshots");
|
||||
|
||||
filename = filename.replaceAll("\\.png$", suffix + ".png");
|
||||
String absolutePath =
|
||||
String.format("%s/%s", dir.getAbsolutePath(), filename);
|
||||
|
||||
File parent = new File(absolutePath).getParentFile();
|
||||
if (!parent.exists() && !parent.mkdirs()) throw new RuntimeException(
|
||||
String.format("Could not create dir: %s",
|
||||
parent.getAbsolutePath()));
|
||||
|
||||
FileOutputStream out = new FileOutputStream(absolutePath);
|
||||
bitmap.compress(Bitmap.CompressFormat.PNG, 100, out);
|
||||
|
||||
return absolutePath;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,99 @@
|
||||
/*
|
||||
* 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()
|
||||
{
|
||||
return createEmptyHabit(null);
|
||||
}
|
||||
|
||||
public Habit createEmptyHabit(Long id)
|
||||
{
|
||||
Habit habit = modelFactory.buildHabit();
|
||||
habit.setName("Meditate");
|
||||
habit.setDescription("Did you meditate this morning?");
|
||||
habit.setColor(3);
|
||||
habit.setFrequency(Frequency.DAILY);
|
||||
habit.setId(id);
|
||||
habitList.add(habit);
|
||||
return habit;
|
||||
}
|
||||
|
||||
public Habit createLongHabit()
|
||||
{
|
||||
Habit habit = createEmptyHabit();
|
||||
habit.setFrequency(new Frequency(3, 7));
|
||||
habit.setColor(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;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* 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.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 HabitsApplicationTest extends BaseAndroidTest
|
||||
{
|
||||
@Test
|
||||
public void test_getLogcat() throws IOException
|
||||
{
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN)
|
||||
return;
|
||||
|
||||
String msg = "LOGCAT TEST";
|
||||
new RuntimeException(msg).printStackTrace();
|
||||
|
||||
BaseSystem system = new BaseSystem(targetContext);
|
||||
String log = system.getLogcat();
|
||||
assertThat(log, containsString(msg));
|
||||
}
|
||||
}
|
||||
@@ -1,178 +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.support.test.InstrumentationRegistry;
|
||||
|
||||
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.openContextualActionModeOverflowMenu;
|
||||
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.ViewMatchers.isDisplayed;
|
||||
import static android.support.test.espresso.matcher.ViewMatchers.withContentDescription;
|
||||
import static android.support.test.espresso.matcher.ViewMatchers.withId;
|
||||
import static android.support.test.espresso.matcher.ViewMatchers.withText;
|
||||
import static org.hamcrest.Matchers.allOf;
|
||||
import static org.hamcrest.Matchers.instanceOf;
|
||||
import static org.hamcrest.Matchers.is;
|
||||
import static org.hamcrest.Matchers.not;
|
||||
import static org.isoron.uhabits.HabitMatchers.containsHabit;
|
||||
import static org.isoron.uhabits.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));
|
||||
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);
|
||||
clickActionModeMenuItem(R.string.delete);
|
||||
onView(withText("OK"))
|
||||
.perform(click());
|
||||
assertHabitsDontExist(names);
|
||||
}
|
||||
|
||||
public static void clickActionModeMenuItem(int stringId)
|
||||
{
|
||||
try
|
||||
{
|
||||
onView(withText(stringId)).perform(click());
|
||||
}
|
||||
catch (Exception e1)
|
||||
{
|
||||
try
|
||||
{
|
||||
onView(withContentDescription(stringId)).perform(click());
|
||||
}
|
||||
catch(Exception e2)
|
||||
{
|
||||
openContextualActionModeOverflowMenu();
|
||||
onView(withText(stringId)).perform(click());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,200 +0,0 @@
|
||||
package org.isoron.uhabits;
|
||||
|
||||
import android.content.Context;
|
||||
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.models.Habit;
|
||||
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.openActionBarOverflowOrOptionsMenu;
|
||||
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.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 android.support.test.espresso.matcher.ViewMatchers.withText;
|
||||
import static org.hamcrest.Matchers.allOf;
|
||||
import static org.hamcrest.Matchers.endsWith;
|
||||
import static org.hamcrest.Matchers.instanceOf;
|
||||
import static org.hamcrest.Matchers.is;
|
||||
import static org.isoron.uhabits.HabitMatchers.withName;
|
||||
import static org.isoron.uhabits.HabitViewActions.clickAtRandomLocations;
|
||||
import static org.isoron.uhabits.HabitViewActions.toggleAllCheckmarks;
|
||||
import static org.isoron.uhabits.MainActivityActions.addHabit;
|
||||
import static org.isoron.uhabits.MainActivityActions.assertHabitExists;
|
||||
import static org.isoron.uhabits.MainActivityActions.assertHabitsDontExist;
|
||||
import static org.isoron.uhabits.MainActivityActions.assertHabitsExist;
|
||||
import static org.isoron.uhabits.MainActivityActions.clickActionModeMenuItem;
|
||||
import static org.isoron.uhabits.MainActivityActions.deleteHabit;
|
||||
import static org.isoron.uhabits.MainActivityActions.deleteHabits;
|
||||
import static org.isoron.uhabits.MainActivityActions.selectHabit;
|
||||
import static org.isoron.uhabits.MainActivityActions.selectHabits;
|
||||
import static org.isoron.uhabits.MainActivityActions.typeHabitData;
|
||||
import static org.isoron.uhabits.ShowHabitActivityActions.openHistoryEditor;
|
||||
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
@LargeTest
|
||||
public class MainTest
|
||||
{
|
||||
@Rule
|
||||
public IntentsTestRule<MainActivity> activityRule = new IntentsTestRule<>(
|
||||
MainActivity.class);
|
||||
|
||||
@Before
|
||||
public void skipTutorial()
|
||||
{
|
||||
try
|
||||
{
|
||||
for (int i = 0; i < 10; i++)
|
||||
onView(allOf(withClassName(endsWith("AppCompatImageButton")),
|
||||
isDisplayed())).perform(click());
|
||||
}
|
||||
catch (NoMatchingViewException e)
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testArchiveHabits()
|
||||
{
|
||||
List<String> names = new LinkedList<>();
|
||||
Context context = InstrumentationRegistry.getTargetContext();
|
||||
|
||||
for(int i = 0; i < 3; i++)
|
||||
names.add(addHabit());
|
||||
|
||||
selectHabits(names);
|
||||
|
||||
clickActionModeMenuItem(R.string.archive);
|
||||
assertHabitsDontExist(names);
|
||||
|
||||
openActionBarOverflowOrOptionsMenu(context);
|
||||
onView(withText(R.string.show_archived))
|
||||
.perform(click());
|
||||
|
||||
assertHabitsExist(names);
|
||||
selectHabits(names);
|
||||
clickActionModeMenuItem(R.string.unarchive);
|
||||
|
||||
openActionBarOverflowOrOptionsMenu(context);
|
||||
onView(withText(R.string.show_archived))
|
||||
.perform(click());
|
||||
|
||||
assertHabitsExist(names);
|
||||
deleteHabits(names);
|
||||
}
|
||||
|
||||
@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()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAddHabitAndViewStats()
|
||||
{
|
||||
String name = addHabit(true);
|
||||
|
||||
onData(allOf(is(instanceOf(Habit.class)), withName(name)))
|
||||
.onChildView(withId(R.id.llButtons))
|
||||
.perform(toggleAllCheckmarks());
|
||||
|
||||
onData(allOf(is(instanceOf(Habit.class)), withName(name)))
|
||||
.onChildView(withId(R.id.label))
|
||||
.perform(click());
|
||||
|
||||
onView(withId(R.id.scoreView))
|
||||
.perform(swipeRight());
|
||||
|
||||
onView(withId(R.id.punchcardView))
|
||||
.perform(scrollTo());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEditHabit()
|
||||
{
|
||||
String name = addHabit();
|
||||
|
||||
onData(allOf(is(instanceOf(Habit.class)), withName(name)))
|
||||
.onChildView(withId(R.id.label))
|
||||
.perform(longClick());
|
||||
|
||||
clickActionModeMenuItem(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);
|
||||
clickActionModeMenuItem(R.string.color_picker_default_title);
|
||||
pressBack();
|
||||
|
||||
deleteHabit(modifiedName);
|
||||
}
|
||||
|
||||
@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());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSettings()
|
||||
{
|
||||
Context context = InstrumentationRegistry.getContext();
|
||||
openActionBarOverflowOrOptionsMenu(context);
|
||||
onView(withText(R.string.settings)).perform(click());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAbout()
|
||||
{
|
||||
Context context = InstrumentationRegistry.getContext();
|
||||
openActionBarOverflowOrOptionsMenu(context);
|
||||
onView(withText(R.string.about)).perform(click());
|
||||
onView(isRoot()).perform(swipeUp());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
/*
|
||||
* 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 FrequencyChartTest extends BaseViewTest
|
||||
{
|
||||
public static final String BASE_PATH = "common/FrequencyChart/";
|
||||
|
||||
private FrequencyChart view;
|
||||
|
||||
@Override
|
||||
@Before
|
||||
public void setUp()
|
||||
{
|
||||
super.setUp();
|
||||
|
||||
fixtures.purgeHabits(habitList);
|
||||
Habit habit = fixtures.createLongHabit();
|
||||
|
||||
view = new FrequencyChart(targetContext);
|
||||
view.setFrequency(habit.getRepetitions().getWeekdayFrequency());
|
||||
view.setColor(ColorUtils.getAndroidTestColor(habit.getColor()));
|
||||
measureView(view, dpToPixels(300), dpToPixels(100));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRender() throws Throwable
|
||||
{
|
||||
assertRenders(view, BASE_PATH + "render.png");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRender_withDataOffset() throws Throwable
|
||||
{
|
||||
view.onScroll(null, null, -dpToPixels(150), 0);
|
||||
view.invalidate();
|
||||
|
||||
assertRenders(view, BASE_PATH + "renderDataOffset.png");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRender_withDifferentSize() throws Throwable
|
||||
{
|
||||
measureView(view, dpToPixels(200), dpToPixels(200));
|
||||
assertRenders(view, BASE_PATH + "renderDifferentSize.png");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRender_withTransparentBackground() throws Throwable
|
||||
{
|
||||
view.setIsBackgroundTransparent(true);
|
||||
assertRenders(view, BASE_PATH + "renderTransparent.png");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,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");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
/*
|
||||
* Copyright (C) 2016 Álinson Santos Xavier <isoron@gmail.com>
|
||||
*
|
||||
* This file is part of Loop Habit Tracker.
|
||||
*
|
||||
* Loop Habit Tracker is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation, either version 3 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* Loop Habit Tracker is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.isoron.uhabits.activities.common.views;
|
||||
|
||||
import android.graphics.*;
|
||||
import android.support.test.runner.*;
|
||||
import android.test.suitebuilder.annotation.*;
|
||||
|
||||
import org.isoron.uhabits.*;
|
||||
import org.isoron.uhabits.utils.*;
|
||||
import org.junit.*;
|
||||
import org.junit.runner.*;
|
||||
|
||||
import java.io.*;
|
||||
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
@MediumTest
|
||||
public class RingViewTest extends BaseViewTest
|
||||
{
|
||||
private static final String BASE_PATH = "common/RingView/";
|
||||
|
||||
private RingView view;
|
||||
|
||||
@Override
|
||||
@Before
|
||||
public void setUp()
|
||||
{
|
||||
super.setUp();
|
||||
|
||||
view = new RingView(targetContext);
|
||||
view.setPercentage(0.6f);
|
||||
view.setText("60%");
|
||||
view.setColor(ColorUtils.getAndroidTestColor(0));
|
||||
view.setBackgroundColor(Color.WHITE);
|
||||
view.setThickness(dpToPixels(3));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRender_base() throws IOException
|
||||
{
|
||||
measureView(view, dpToPixels(100), dpToPixels(100));
|
||||
assertRenders(view, BASE_PATH + "render.png");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRender_withDifferentParams() throws IOException
|
||||
{
|
||||
view.setPercentage(0.25f);
|
||||
view.setColor(ColorUtils.getAndroidTestColor(5));
|
||||
|
||||
measureView(view, dpToPixels(200), dpToPixels(200));
|
||||
assertRenders(view, BASE_PATH + "renderDifferentParams.png");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,108 @@
|
||||
/*
|
||||
* Copyright (C) 2016 Álinson Santos Xavier <isoron@gmail.com>
|
||||
*
|
||||
* This file is part of Loop Habit Tracker.
|
||||
*
|
||||
* Loop Habit Tracker is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation, either version 3 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* Loop Habit Tracker is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.isoron.uhabits.activities.common.views;
|
||||
|
||||
import android.support.test.runner.*;
|
||||
import android.test.suitebuilder.annotation.*;
|
||||
import android.util.*;
|
||||
|
||||
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 ScoreChartTest extends BaseViewTest
|
||||
{
|
||||
private static final String BASE_PATH = "common/ScoreChart/";
|
||||
|
||||
private Habit habit;
|
||||
|
||||
private ScoreChart view;
|
||||
|
||||
@Override
|
||||
@Before
|
||||
public void setUp()
|
||||
{
|
||||
super.setUp();
|
||||
|
||||
fixtures.purgeHabits(habitList);
|
||||
habit = fixtures.createLongHabit();
|
||||
|
||||
view = new ScoreChart(targetContext);
|
||||
view.setScores(habit.getScores().toList());
|
||||
view.setColor(ColorUtils.getColor(targetContext, habit.getColor()));
|
||||
view.setBucketSize(7);
|
||||
measureView(view, dpToPixels(300), dpToPixels(200));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRender() throws Throwable
|
||||
{
|
||||
Log.d("HabitScoreViewTest",
|
||||
String.format("height=%d", dpToPixels(100)));
|
||||
assertRenders(view, BASE_PATH + "render.png");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRender_withDataOffset() throws Throwable
|
||||
{
|
||||
view.onScroll(null, null, -dpToPixels(150), 0);
|
||||
view.invalidate();
|
||||
|
||||
assertRenders(view, BASE_PATH + "renderDataOffset.png");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRender_withDifferentSize() throws Throwable
|
||||
{
|
||||
measureView(view, dpToPixels(200), dpToPixels(200));
|
||||
assertRenders(view, BASE_PATH + "renderDifferentSize.png");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRender_withMonthlyBucket() throws Throwable
|
||||
{
|
||||
view.setScores(habit.getScores().groupBy(DateUtils.TruncateField.MONTH));
|
||||
view.setBucketSize(30);
|
||||
view.invalidate();
|
||||
|
||||
assertRenders(view, BASE_PATH + "renderMonthly.png");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRender_withTransparentBackground() throws Throwable
|
||||
{
|
||||
view.setIsTransparencyEnabled(true);
|
||||
assertRenders(view, BASE_PATH + "renderTransparent.png");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRender_withYearlyBucket() throws Throwable
|
||||
{
|
||||
view.setScores(habit.getScores().groupBy(DateUtils.TruncateField.YEAR));
|
||||
view.setBucketSize(365);
|
||||
view.invalidate();
|
||||
|
||||
assertRenders(view, BASE_PATH + "renderYearly.png");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
/*
|
||||
* Copyright (C) 2016 Álinson Santos Xavier <isoron@gmail.com>
|
||||
*
|
||||
* This file is part of Loop Habit Tracker.
|
||||
*
|
||||
* Loop Habit Tracker is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation, either version 3 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* Loop Habit Tracker is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.isoron.uhabits.activities.common.views;
|
||||
|
||||
import android.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 StreakChartTest extends BaseViewTest
|
||||
{
|
||||
private static final String BASE_PATH = "common/StreakChart/";
|
||||
|
||||
private StreakChart view;
|
||||
|
||||
@Override
|
||||
@Before
|
||||
public void setUp()
|
||||
{
|
||||
super.setUp();
|
||||
|
||||
fixtures.purgeHabits(habitList);
|
||||
Habit habit = fixtures.createLongHabit();
|
||||
|
||||
view = new StreakChart(targetContext);
|
||||
view.setColor(ColorUtils.getAndroidTestColor(habit.getColor()));
|
||||
view.setStreaks(habit.getStreaks().getBest(5));
|
||||
measureView(view, dpToPixels(300), dpToPixels(100));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRender() throws Throwable
|
||||
{
|
||||
assertRenders(view, BASE_PATH + "render.png");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRender_withSmallSize() throws Throwable
|
||||
{
|
||||
measureView(view, dpToPixels(100), dpToPixels(100));
|
||||
assertRenders(view, BASE_PATH + "renderSmallSize.png");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRender_withTransparentBackground() throws Throwable
|
||||
{
|
||||
view.setIsBackgroundTransparent(true);
|
||||
assertRenders(view, BASE_PATH + "renderTransparent.png");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,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.015f);
|
||||
|
||||
latch = new CountDownLatch(1);
|
||||
view = new CheckmarkButtonView(targetContext);
|
||||
view.setValue(Checkmark.UNCHECKED);
|
||||
view.setColor(ColorUtils.getAndroidTestColor(5));
|
||||
|
||||
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,98 @@
|
||||
/*
|
||||
* 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.setButtonCount(4);
|
||||
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,12 +17,14 @@
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.isoron.uhabits;
|
||||
package org.isoron.uhabits.espresso;
|
||||
|
||||
import android.preference.Preference;
|
||||
import android.view.View;
|
||||
import android.widget.Adapter;
|
||||
import android.widget.AdapterView;
|
||||
|
||||
import org.hamcrest.BaseMatcher;
|
||||
import org.hamcrest.Description;
|
||||
import org.hamcrest.Matcher;
|
||||
import org.hamcrest.TypeSafeMatcher;
|
||||
@@ -37,7 +39,7 @@ public class HabitMatchers
|
||||
@Override
|
||||
public boolean matchesSafely(Habit habit)
|
||||
{
|
||||
return habit.name.equals(name);
|
||||
return habit.getName().equals(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -49,7 +51,7 @@ public class HabitMatchers
|
||||
@Override
|
||||
public void describeMismatchSafely(Habit habit, Description description)
|
||||
{
|
||||
description.appendText("was ").appendText(habit.name);
|
||||
description.appendText("was ").appendText(habit.getName());
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -76,4 +78,23 @@ public class HabitMatchers
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public static Matcher<?> isPreferenceWithText(final String text)
|
||||
{
|
||||
return (Matcher<?>) new BaseMatcher()
|
||||
{
|
||||
@Override
|
||||
public boolean matches(Object o)
|
||||
{
|
||||
if(!(o instanceof Preference)) return false;
|
||||
return o.toString().contains(text);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void describeTo(Description description)
|
||||
{
|
||||
description.appendText(String.format("is preference with text '%s'", text));
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -17,7 +17,7 @@
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.isoron.uhabits;
|
||||
package org.isoron.uhabits.espresso;
|
||||
|
||||
import android.support.test.espresso.UiController;
|
||||
import android.support.test.espresso.ViewAction;
|
||||
@@ -32,6 +32,7 @@ import android.widget.LinearLayout;
|
||||
import android.widget.TextView;
|
||||
|
||||
import org.hamcrest.Matcher;
|
||||
import org.isoron.uhabits.R;
|
||||
|
||||
import java.security.InvalidParameterException;
|
||||
import java.util.Random;
|
||||
@@ -60,7 +61,7 @@ public class HabitViewActions
|
||||
@Override
|
||||
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");
|
||||
|
||||
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.hide_archived);
|
||||
|
||||
assertHabitsExist(names);
|
||||
selectHabits(names);
|
||||
clickMenuItem(R.string.unarchive);
|
||||
|
||||
clickMenuItem(R.string.hide_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,18 +17,21 @@
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.isoron.uhabits;
|
||||
package org.isoron.uhabits.espresso;
|
||||
|
||||
import android.support.test.espresso.matcher.ViewMatchers;
|
||||
|
||||
import org.isoron.uhabits.R;
|
||||
|
||||
import static android.support.test.espresso.Espresso.onView;
|
||||
import static android.support.test.espresso.action.ViewActions.click;
|
||||
import static android.support.test.espresso.action.ViewActions.scrollTo;
|
||||
import static android.support.test.espresso.matcher.ViewMatchers.withId;
|
||||
|
||||
public class ShowHabitActivityActions
|
||||
{
|
||||
public static void openHistoryEditor()
|
||||
{
|
||||
onView(withId(R.id.btEditHistory))
|
||||
onView(ViewMatchers.withId(R.id.edit))
|
||||
.perform(scrollTo(), click());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,124 @@
|
||||
/*
|
||||
* 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.content.Context;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.os.IBinder;
|
||||
import android.os.PowerManager;
|
||||
import android.support.test.runner.AndroidJUnitRunner;
|
||||
import android.util.Log;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
public final class SystemHelper extends AndroidJUnitRunner
|
||||
{
|
||||
private static final String ANIMATION_PERMISSION = "android.permission.SET_ANIMATION_SCALE";
|
||||
private static final float DISABLED = 0.0f;
|
||||
private static final float DEFAULT = 1.0f;
|
||||
|
||||
private final Context context;
|
||||
private PowerManager.WakeLock wakeLock;
|
||||
|
||||
SystemHelper(Context context)
|
||||
{
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
void acquireWakeLock()
|
||||
{
|
||||
PowerManager power = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
|
||||
wakeLock = power.newWakeLock(PowerManager.FULL_WAKE_LOCK |
|
||||
PowerManager.ACQUIRE_CAUSES_WAKEUP |
|
||||
PowerManager.ON_AFTER_RELEASE, getClass().getSimpleName());
|
||||
wakeLock.acquire();
|
||||
}
|
||||
|
||||
void releaseWakeLock()
|
||||
{
|
||||
if(wakeLock != null)
|
||||
wakeLock.release();
|
||||
}
|
||||
|
||||
void unlockScreen()
|
||||
{
|
||||
Log.i("SystemHelper", "Trying to unlock screen");
|
||||
try
|
||||
{
|
||||
KeyguardManager mKeyGuardManager =
|
||||
(KeyguardManager) context.getSystemService(Context.KEYGUARD_SERVICE);
|
||||
KeyguardManager.KeyguardLock mLock = mKeyGuardManager.newKeyguardLock("lock");
|
||||
mLock.disableKeyguard();
|
||||
Log.e("SystemHelper", "Successfully unlocked screen");
|
||||
} catch (Exception e)
|
||||
{
|
||||
Log.e("SystemHelper", "Could not unlock screen");
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
void disableAllAnimations()
|
||||
{
|
||||
Log.i("SystemHelper", "Trying to disable animations");
|
||||
int permStatus = context.checkCallingOrSelfPermission(ANIMATION_PERMISSION);
|
||||
if (permStatus == PackageManager.PERMISSION_GRANTED) setSystemAnimationsScale(DISABLED);
|
||||
else Log.e("SystemHelper", "Permission denied");
|
||||
|
||||
}
|
||||
|
||||
void enableAllAnimations()
|
||||
{
|
||||
int permStatus = context.checkCallingOrSelfPermission(ANIMATION_PERMISSION);
|
||||
if (permStatus == PackageManager.PERMISSION_GRANTED)
|
||||
{
|
||||
setSystemAnimationsScale(DEFAULT);
|
||||
}
|
||||
}
|
||||
|
||||
private void setSystemAnimationsScale(float animationScale)
|
||||
{
|
||||
try
|
||||
{
|
||||
Class<?> windowManagerStubClazz = Class.forName("android.view.IWindowManager$Stub");
|
||||
Method asInterface =
|
||||
windowManagerStubClazz.getDeclaredMethod("asInterface", IBinder.class);
|
||||
Class<?> serviceManagerClazz = Class.forName("android.os.ServiceManager");
|
||||
Method getService = serviceManagerClazz.getDeclaredMethod("getService", String.class);
|
||||
Class<?> windowManagerClazz = Class.forName("android.view.IWindowManager");
|
||||
Method setAnimationScales =
|
||||
windowManagerClazz.getDeclaredMethod("setAnimationScales", float[].class);
|
||||
Method getAnimationScales = windowManagerClazz.getDeclaredMethod("getAnimationScales");
|
||||
|
||||
IBinder windowManagerBinder = (IBinder) getService.invoke(null, "window");
|
||||
Object windowManagerObj = asInterface.invoke(null, windowManagerBinder);
|
||||
float[] currentScales = (float[]) getAnimationScales.invoke(windowManagerObj);
|
||||
for (int i = 0; i < currentScales.length; i++)
|
||||
currentScales[i] = animationScale;
|
||||
|
||||
setAnimationScales.invoke(windowManagerObj, new Object[]{currentScales});
|
||||
Log.i("SystemHelper", "All animations successfully disabled");
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Log.e("SystemHelper", "Could not change animation scale to " + animationScale + " :'(");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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.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 java.util.zip.*;
|
||||
|
||||
import static junit.framework.Assert.*;
|
||||
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
@MediumTest
|
||||
public class HabitsCSVExporterTest extends BaseAndroidTest
|
||||
{
|
||||
private File baseDir;
|
||||
|
||||
@Before
|
||||
public void setUp()
|
||||
{
|
||||
super.setUp();
|
||||
|
||||
fixtures.purgeHabits(habitList);
|
||||
fixtures.createShortHabit();
|
||||
fixtures.createEmptyHabit();
|
||||
|
||||
Context targetContext = InstrumentationRegistry.getTargetContext();
|
||||
baseDir = targetContext.getCacheDir();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testExportCSV() throws IOException
|
||||
{
|
||||
List<Habit> selected = new LinkedList<>();
|
||||
for (Habit h : habitList) selected.add(h);
|
||||
|
||||
HabitsCSVExporter exporter =
|
||||
new HabitsCSVExporter(habitList, selected, baseDir);
|
||||
String filename = exporter.writeArchive();
|
||||
assertAbsolutePathExists(filename);
|
||||
|
||||
File archive = new File(filename);
|
||||
unzip(archive);
|
||||
|
||||
assertPathExists("Habits.csv");
|
||||
assertPathExists("001 Wake up early");
|
||||
assertPathExists("001 Wake up early/Checkmarks.csv");
|
||||
assertPathExists("001 Wake up early/Scores.csv");
|
||||
assertPathExists("002 Meditate/Checkmarks.csv");
|
||||
assertPathExists("002 Meditate/Scores.csv");
|
||||
assertPathExists("Checkmarks.csv");
|
||||
assertPathExists("Scores.csv");
|
||||
}
|
||||
|
||||
private void assertAbsolutePathExists(String s)
|
||||
{
|
||||
File file = new File(s);
|
||||
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();
|
||||
}
|
||||
}
|
||||
159
app/src/androidTest/java/org/isoron/uhabits/io/ImportTest.java
Normal file
@@ -0,0 +1,159 @@
|
||||
/*
|
||||
* 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 Context context;
|
||||
|
||||
@Override
|
||||
@Before
|
||||
public void setUp()
|
||||
{
|
||||
super.setUp();
|
||||
DateUtils.setFixedLocalTime(null);
|
||||
fixtures.purgeHabits(habitList);
|
||||
context = InstrumentationRegistry.getInstrumentation().getContext();
|
||||
}
|
||||
|
||||
@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 = File.createTempFile("asset", "");
|
||||
copyAssetToFile(assetFilename, file);
|
||||
assertTrue(file.exists());
|
||||
assertTrue(file.canRead());
|
||||
|
||||
GenericImporter importer = component.getGenericImporter();
|
||||
assertThat(importer.canHandle(file), is(true));
|
||||
|
||||
importer.importHabitsFromFile(file);
|
||||
|
||||
file.delete();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,240 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
import android.support.test.runner.*;
|
||||
import android.test.suitebuilder.annotation.*;
|
||||
|
||||
import org.hamcrest.*;
|
||||
import org.isoron.uhabits.*;
|
||||
import org.junit.*;
|
||||
import org.junit.runner.*;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.*;
|
||||
|
||||
import static junit.framework.Assert.*;
|
||||
import static org.hamcrest.CoreMatchers.*;
|
||||
import static org.hamcrest.MatcherAssert.*;
|
||||
import static org.hamcrest.core.IsEqual.equalTo;
|
||||
import static org.isoron.uhabits.models.HabitList.Order.*;
|
||||
|
||||
@SuppressWarnings("JavaDoc")
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
@MediumTest
|
||||
public class HabitListTest extends BaseAndroidTest
|
||||
{
|
||||
private ArrayList<Habit> habitsArray;
|
||||
|
||||
private HabitList activeHabits;
|
||||
|
||||
private HabitList reminderHabits;
|
||||
|
||||
@Override
|
||||
public void setUp()
|
||||
{
|
||||
super.setUp();
|
||||
habitList.removeAll();
|
||||
|
||||
habitsArray = new ArrayList<>();
|
||||
|
||||
for (int i = 0; i < 10; i++)
|
||||
{
|
||||
Habit habit = fixtures.createEmptyHabit((long) i);
|
||||
habitsArray.add(habit);
|
||||
|
||||
if (i % 3 == 0)
|
||||
habit.setReminder(new Reminder(8, 30, WeekdayList.EVERY_DAY));
|
||||
|
||||
habitList.update(habit);
|
||||
}
|
||||
|
||||
habitsArray.get(0).setArchived(true);
|
||||
habitsArray.get(1).setArchived(true);
|
||||
habitsArray.get(4).setArchived(true);
|
||||
habitsArray.get(7).setArchived(true);
|
||||
|
||||
activeHabits = habitList.getFiltered(new HabitMatcherBuilder().build());
|
||||
|
||||
reminderHabits = habitList.getFiltered(new HabitMatcherBuilder()
|
||||
.setArchivedAllowed(true)
|
||||
.setReminderRequired(true)
|
||||
.build());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_size()
|
||||
{
|
||||
assertThat(habitList.size(), equalTo(10));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_countActive()
|
||||
{
|
||||
assertThat(activeHabits.size(), equalTo(6));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_getByPosition()
|
||||
{
|
||||
assertThat(habitList.getByPosition(0), equalTo(habitsArray.get(0)));
|
||||
assertThat(habitList.getByPosition(3), equalTo(habitsArray.get(3)));
|
||||
assertThat(habitList.getByPosition(9), equalTo(habitsArray.get(9)));
|
||||
|
||||
assertThat(activeHabits.getByPosition(0), equalTo(habitsArray.get(2)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_getHabitsWithReminder()
|
||||
{
|
||||
assertThat(reminderHabits.size(), equalTo(4));
|
||||
assertThat(reminderHabits.getByPosition(1),
|
||||
equalTo(habitsArray.get(3)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_get_withInvalidId()
|
||||
{
|
||||
assertThat(habitList.getById(100L), is(nullValue()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_get_withValidId()
|
||||
{
|
||||
Habit habit1 = habitsArray.get(0);
|
||||
Habit habit2 = habitList.getById(habit1.getId());
|
||||
assertThat(habit1, equalTo(habit2));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_reorder()
|
||||
{
|
||||
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]));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_writeCSV() throws IOException
|
||||
{
|
||||
habitList.removeAll();
|
||||
|
||||
Habit h1 = fixtures.createEmptyHabit();
|
||||
h1.setName("Meditate");
|
||||
h1.setDescription("Did you meditate this morning?");
|
||||
h1.setFrequency(Frequency.DAILY);
|
||||
h1.setColor(3);
|
||||
|
||||
Habit h2 = fixtures.createEmptyHabit();
|
||||
h2.setName("Wake up early");
|
||||
h2.setDescription("Did you wake up before 6am?");
|
||||
h2.setFrequency(new Frequency(2, 3));
|
||||
h2.setColor(5);
|
||||
|
||||
habitList.update(h1);
|
||||
habitList.update(h2);
|
||||
|
||||
String expectedCSV =
|
||||
"Position,Name,Description,NumRepetitions,Interval,Color\n" +
|
||||
"001,Meditate,Did you meditate this morning?,1,1,#AFB42B\n" +
|
||||
"002,Wake up early,Did you wake up before 6am?,2,3,#00897B\n";
|
||||
|
||||
StringWriter writer = new StringWriter();
|
||||
habitList.writeCSV(writer);
|
||||
|
||||
MatcherAssert.assertThat(writer.toString(), equalTo(expectedCSV));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_ordering()
|
||||
{
|
||||
habitList.removeAll();
|
||||
|
||||
Habit h3 = fixtures.createEmptyHabit();
|
||||
h3.setName("C Habit");
|
||||
h3.setColor(0);
|
||||
habitList.update(h3);
|
||||
|
||||
Habit h1 = fixtures.createEmptyHabit();
|
||||
h1.setName("A Habit");
|
||||
h1.setColor(2);
|
||||
habitList.update(h1);
|
||||
|
||||
Habit h4 = fixtures.createEmptyHabit();
|
||||
h4.setName("D Habit");
|
||||
h4.setColor(1);
|
||||
habitList.update(h4);
|
||||
|
||||
Habit h2 = fixtures.createEmptyHabit();
|
||||
h2.setName("B Habit");
|
||||
h2.setColor(2);
|
||||
habitList.update(h2);
|
||||
|
||||
habitList.setOrder(BY_POSITION);
|
||||
assertThat(habitList.getByPosition(0), equalTo(h3));
|
||||
assertThat(habitList.getByPosition(1), equalTo(h1));
|
||||
assertThat(habitList.getByPosition(2), equalTo(h4));
|
||||
assertThat(habitList.getByPosition(3), equalTo(h2));
|
||||
|
||||
habitList.setOrder(BY_NAME);
|
||||
assertThat(habitList.getByPosition(0), equalTo(h1));
|
||||
assertThat(habitList.getByPosition(1), equalTo(h2));
|
||||
assertThat(habitList.getByPosition(2), equalTo(h3));
|
||||
assertThat(habitList.getByPosition(3), equalTo(h4));
|
||||
|
||||
habitList.remove(h1);
|
||||
habitList.add(h1);
|
||||
assertThat(habitList.getByPosition(0), equalTo(h1));
|
||||
|
||||
habitList.setOrder(BY_COLOR);
|
||||
assertThat(habitList.getByPosition(0), equalTo(h3));
|
||||
assertThat(habitList.getByPosition(1), equalTo(h4));
|
||||
assertThat(habitList.getByPosition(2), equalTo(h1));
|
||||
assertThat(habitList.getByPosition(3), equalTo(h2));
|
||||
}
|
||||
}
|
||||
@@ -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,162 @@
|
||||
/*
|
||||
* 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));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFixRecords() throws Exception
|
||||
{
|
||||
long day = DateUtils.millisecondsInOneDay;
|
||||
long from = DateUtils.getStartOfToday();
|
||||
long to = from + 5 * day;
|
||||
|
||||
List<CheckmarkRecord> original, actual, expected;
|
||||
HabitRecord habit = new HabitRecord();
|
||||
|
||||
original = new ArrayList<>();
|
||||
original.add(new CheckmarkRecord(habit, from + 8*day, 2));
|
||||
original.add(new CheckmarkRecord(habit, from + 5*day, 0));
|
||||
original.add(new CheckmarkRecord(habit, from + 4*day, 0));
|
||||
original.add(new CheckmarkRecord(habit, from + 4*day, 2));
|
||||
original.add(new CheckmarkRecord(habit, from + 3*day, 2));
|
||||
original.add(new CheckmarkRecord(habit, from + 2*day, 1));
|
||||
original.add(new CheckmarkRecord(habit, from + 2*day + 100, 1));
|
||||
original.add(new CheckmarkRecord(habit, from, 0));
|
||||
original.add(new CheckmarkRecord(habit, from, 2));
|
||||
original.add(new CheckmarkRecord(habit, from - day, 2));
|
||||
|
||||
actual = SQLiteCheckmarkList.fixRecords(original, habit, from, to);
|
||||
|
||||
expected = new ArrayList<>();
|
||||
expected.add(new CheckmarkRecord(habit, from + 5*day, 0));
|
||||
expected.add(new CheckmarkRecord(habit, from + 4*day, 2));
|
||||
expected.add(new CheckmarkRecord(habit, from + 3*day, 2));
|
||||
expected.add(new CheckmarkRecord(habit, from + 2*day, 1));
|
||||
expected.add(new CheckmarkRecord(habit, from + day, 0));
|
||||
expected.add(new CheckmarkRecord(habit, from, 2));
|
||||
|
||||
assertThat(actual, equalTo(expected));
|
||||
}
|
||||
|
||||
private List<CheckmarkRecord> getAllRecords()
|
||||
{
|
||||
return new Select()
|
||||
.from(CheckmarkRecord.class)
|
||||
.where("habit = ?", habit.getId())
|
||||
.orderBy("timestamp desc")
|
||||
.execute();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,177 @@
|
||||
/*
|
||||
* 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 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));
|
||||
}
|
||||
|
||||
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,156 @@
|
||||
/*
|
||||
* 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 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 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 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_concurrent() throws Exception
|
||||
{
|
||||
Runnable block1 = () -> scores.invalidateNewerThan(0);
|
||||
Runnable block2 =
|
||||
() -> assertThat(scores.getByInterval(today, today).size(),
|
||||
equalTo(1));
|
||||
runConcurrently(block1, block2);
|
||||
}
|
||||
|
||||
@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));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetTodayValue_concurrent() throws Exception
|
||||
{
|
||||
Runnable block1 = () -> scores.invalidateNewerThan(0);
|
||||
Runnable block2 =
|
||||
() -> assertThat(scores.getTodayValue(), equalTo(18407827));
|
||||
|
||||
runConcurrently(block1, block2);
|
||||
}
|
||||
|
||||
@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));
|
||||
}
|
||||
|
||||
private List<ScoreRecord> getAllRecords()
|
||||
{
|
||||
return new Select()
|
||||
.from(ScoreRecord.class)
|
||||
.where("habit = ?", habit.getId())
|
||||
.orderBy("timestamp desc")
|
||||
.execute();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright (C) 2017 Álinson Santos Xavier <isoron@gmail.com>
|
||||
*
|
||||
* This file is part of Loop Habit Tracker.
|
||||
*
|
||||
* Loop Habit Tracker is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation, either version 3 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* Loop Habit Tracker is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.isoron.uhabits.performance;
|
||||
|
||||
import android.support.test.filters.*;
|
||||
|
||||
import org.isoron.uhabits.*;
|
||||
import org.isoron.uhabits.models.*;
|
||||
import org.junit.*;
|
||||
|
||||
@MediumTest
|
||||
public class PerformanceTest extends BaseAndroidTest
|
||||
{
|
||||
private Habit habit;
|
||||
|
||||
@Override
|
||||
public void setUp()
|
||||
{
|
||||
super.setUp();
|
||||
habit = fixtures.createLongHabit();
|
||||
}
|
||||
|
||||
@Test(timeout = 1000)
|
||||
public void testRepeatedGetTodayValue()
|
||||
{
|
||||
for (int i = 0; i < 100000; i++)
|
||||
{
|
||||
habit.getScores().getTodayValue();
|
||||
habit.getCheckmarks().getTodayValue();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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(targetContext,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(targetContext, filename -> {
|
||||
assertThat(filename, is(not(nullValue())));
|
||||
|
||||
File f = new File(filename);
|
||||
assertTrue(f.exists());
|
||||
assertTrue(f.canRead());
|
||||
});
|
||||
|
||||
taskRunner.execute(task);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
/*
|
||||
* Copyright (C) 2016 Álinson Santos Xavier <isoron@gmail.com>
|
||||
*
|
||||
* This file is part of Loop Habit Tracker.
|
||||
*
|
||||
* Loop Habit Tracker is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation, either version 3 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* Loop Habit Tracker is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.isoron.uhabits.widgets;
|
||||
|
||||
import android.support.test.runner.*;
|
||||
import android.test.suitebuilder.annotation.*;
|
||||
import android.widget.*;
|
||||
|
||||
import org.isoron.uhabits.*;
|
||||
import org.isoron.uhabits.models.*;
|
||||
import org.isoron.uhabits.widgets.*;
|
||||
import org.junit.*;
|
||||
import org.junit.runner.*;
|
||||
|
||||
import static org.hamcrest.MatcherAssert.*;
|
||||
import static org.hamcrest.Matchers.*;
|
||||
import static org.isoron.uhabits.models.Checkmark.*;
|
||||
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
@MediumTest
|
||||
public class CheckmarkWidgetTest extends BaseViewTest
|
||||
{
|
||||
private static final String PATH = "widgets/CheckmarkWidgetView/";
|
||||
|
||||
private Habit habit;
|
||||
|
||||
private CheckmarkList checkmarks;
|
||||
|
||||
private FrameLayout view;
|
||||
|
||||
@Override
|
||||
public void setUp()
|
||||
{
|
||||
super.setUp();
|
||||
habit = fixtures.createShortHabit();
|
||||
checkmarks = habit.getCheckmarks();
|
||||
CheckmarkWidget widget = new CheckmarkWidget(targetContext, 0, habit);
|
||||
view = convertToView(widget, 200, 250);
|
||||
|
||||
assertThat(checkmarks.getTodayValue(), equalTo(CHECKED_EXPLICITLY));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testClick() throws Exception
|
||||
{
|
||||
Button button = (Button) view.findViewById(R.id.button);
|
||||
assertThat(button, is(not(nullValue())));
|
||||
|
||||
// A better test would be to capture the intent, but it doesn't seem
|
||||
// possible to capture intents sent to BroadcastReceivers.
|
||||
button.performClick();
|
||||
sleep(1000);
|
||||
|
||||
assertThat(checkmarks.getTodayValue(), equalTo(UNCHECKED));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIsInstalled()
|
||||
{
|
||||
assertWidgetProviderIsInstalled(CheckmarkWidgetProvider.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRender() throws Exception
|
||||
{
|
||||
assertRenders(view, PATH + "checked.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.widgets;
|
||||
|
||||
import android.support.test.runner.*;
|
||||
import android.test.suitebuilder.annotation.*;
|
||||
import android.widget.*;
|
||||
|
||||
import org.isoron.uhabits.*;
|
||||
import org.isoron.uhabits.models.*;
|
||||
import org.isoron.uhabits.widgets.*;
|
||||
import org.junit.*;
|
||||
import org.junit.runner.*;
|
||||
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
@MediumTest
|
||||
public class FrequencyWidgetTest extends BaseViewTest
|
||||
{
|
||||
private static final String PATH = "widgets/FrequencyWidget/";
|
||||
|
||||
private Habit habit;
|
||||
|
||||
private FrameLayout view;
|
||||
|
||||
@Override
|
||||
public void setUp()
|
||||
{
|
||||
super.setUp();
|
||||
setTheme(R.style.TransparentWidgetTheme);
|
||||
|
||||
habit = fixtures.createLongHabit();
|
||||
FrequencyWidget widget = new FrequencyWidget(targetContext, 0, habit);
|
||||
view = convertToView(widget, 400, 400);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIsInstalled()
|
||||
{
|
||||
assertWidgetProviderIsInstalled(FrequencyWidgetProvider.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRender() throws Exception
|
||||
{
|
||||
assertRenders(view, PATH + "render.png");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,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.widgets;
|
||||
|
||||
import android.support.test.runner.*;
|
||||
import android.test.suitebuilder.annotation.*;
|
||||
import android.widget.*;
|
||||
|
||||
import org.isoron.uhabits.*;
|
||||
import org.isoron.uhabits.models.*;
|
||||
import org.isoron.uhabits.widgets.*;
|
||||
import org.junit.*;
|
||||
import org.junit.runner.*;
|
||||
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
@MediumTest
|
||||
public class HistoryWidgetTest extends BaseViewTest
|
||||
{
|
||||
private static final String PATH = "widgets/HistoryWidget/";
|
||||
|
||||
private Habit habit;
|
||||
|
||||
private FrameLayout view;
|
||||
|
||||
@Override
|
||||
public void setUp()
|
||||
{
|
||||
super.setUp();
|
||||
setTheme(R.style.TransparentWidgetTheme);
|
||||
|
||||
habit = fixtures.createLongHabit();
|
||||
HistoryWidget widget = new HistoryWidget(targetContext, 0, habit);
|
||||
view = convertToView(widget, 400, 400);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIsInstalled()
|
||||
{
|
||||
assertWidgetProviderIsInstalled(HistoryWidgetProvider.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRender() throws Exception
|
||||
{
|
||||
assertRenders(view, PATH + "render.png");
|
||||
}
|
||||
}
|
||||
@@ -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.widgets;
|
||||
|
||||
import android.support.test.runner.*;
|
||||
import android.test.suitebuilder.annotation.*;
|
||||
import android.widget.*;
|
||||
|
||||
import org.isoron.uhabits.*;
|
||||
import org.isoron.uhabits.models.*;
|
||||
import org.junit.*;
|
||||
import org.junit.runner.*;
|
||||
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
@MediumTest
|
||||
public class ScoreWidgetTest extends BaseViewTest
|
||||
{
|
||||
private static final String PATH = "widgets/ScoreWidget/";
|
||||
|
||||
private Habit habit;
|
||||
|
||||
private FrameLayout view;
|
||||
|
||||
@Override
|
||||
public void setUp()
|
||||
{
|
||||
super.setUp();
|
||||
setTheme(R.style.TransparentWidgetTheme);
|
||||
|
||||
habit = fixtures.createLongHabit();
|
||||
ScoreWidget widget = new ScoreWidget(targetContext, 0, habit);
|
||||
view = convertToView(widget, 400, 400);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIsInstalled()
|
||||
{
|
||||
assertWidgetProviderIsInstalled(ScoreWidgetProvider.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRender() throws Exception
|
||||
{
|
||||
assertRenders(view, PATH + "render.png");
|
||||
}
|
||||
}
|
||||