├── .gitignore
├── .travis.yml
├── LICENSE
├── README.md
├── build.gradle
├── buildsystem
├── ci.gradle
├── debug.keystore
└── dependencies.gradle
├── data
├── .gitignore
├── build.gradle
├── proguard-rules.pro
└── src
│ ├── main
│ ├── AndroidManifest.xml
│ └── java
│ │ └── com
│ │ └── fernandocejas
│ │ └── android10
│ │ └── sample
│ │ └── data
│ │ ├── cache
│ │ ├── FileManager.java
│ │ ├── UserCache.java
│ │ ├── UserCacheImpl.java
│ │ └── serializer
│ │ │ └── Serializer.java
│ │ ├── entity
│ │ ├── UserEntity.java
│ │ └── mapper
│ │ │ ├── UserEntityDataMapper.java
│ │ │ └── UserEntityJsonMapper.java
│ │ ├── exception
│ │ ├── NetworkConnectionException.java
│ │ ├── RepositoryErrorBundle.java
│ │ └── UserNotFoundException.java
│ │ ├── executor
│ │ └── JobExecutor.java
│ │ ├── net
│ │ ├── ApiConnection.java
│ │ ├── RestApi.java
│ │ └── RestApiImpl.java
│ │ └── repository
│ │ ├── UserDataRepository.java
│ │ └── datasource
│ │ ├── CloudUserDataStore.java
│ │ ├── DiskUserDataStore.java
│ │ ├── UserDataStore.java
│ │ └── UserDataStoreFactory.java
│ └── test
│ └── java
│ └── com
│ └── fernandocejas
│ └── android10
│ └── sample
│ └── data
│ ├── ApplicationStub.java
│ ├── ApplicationTestCase.java
│ ├── cache
│ ├── FileManagerTest.java
│ └── serializer
│ │ └── SerializerTest.java
│ ├── entity
│ └── mapper
│ │ ├── UserEntityDataMapperTest.java
│ │ └── UserEntityJsonMapperTest.java
│ ├── exception
│ └── RepositoryErrorBundleTest.java
│ └── repository
│ ├── UserDataRepositoryTest.java
│ └── datasource
│ ├── CloudUserDataStoreTest.java
│ ├── DiskUserDataStoreTest.java
│ └── UserDataStoreFactoryTest.java
├── domain
├── build.gradle
└── src
│ ├── main
│ └── java
│ │ └── com
│ │ └── fernandocejas
│ │ └── android10
│ │ └── sample
│ │ └── domain
│ │ ├── User.java
│ │ ├── exception
│ │ ├── DefaultErrorBundle.java
│ │ └── ErrorBundle.java
│ │ ├── executor
│ │ ├── PostExecutionThread.java
│ │ └── ThreadExecutor.java
│ │ ├── interactor
│ │ ├── DefaultObserver.java
│ │ ├── GetUserDetails.java
│ │ ├── GetUserList.java
│ │ └── UseCase.java
│ │ └── repository
│ │ └── UserRepository.java
│ └── test
│ └── java
│ └── com
│ └── fernandocejas
│ └── android10
│ └── sample
│ └── domain
│ ├── UserTest.java
│ ├── exception
│ └── DefaultErrorBundleTest.java
│ └── interactor
│ ├── GetUserDetailsTest.java
│ ├── GetUserListTest.java
│ └── UseCaseTest.java
├── gradle.properties
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── presentation
├── .gitignore
├── build.gradle
├── proguard-rules.pro
└── src
│ ├── androidTest
│ └── java
│ │ └── com
│ │ └── fernandocejas
│ │ └── android10
│ │ └── sample
│ │ └── test
│ │ ├── exception
│ │ └── ErrorMessageFactoryTest.java
│ │ ├── mapper
│ │ └── UserModelDataMapperTest.java
│ │ ├── presenter
│ │ ├── UserDetailsPresenterTest.java
│ │ └── UserListPresenterTest.java
│ │ └── view
│ │ └── activity
│ │ ├── UserDetailsActivityTest.java
│ │ └── UserListActivityTest.java
│ └── main
│ ├── AndroidManifest.xml
│ ├── java
│ └── com
│ │ └── fernandocejas
│ │ └── android10
│ │ └── sample
│ │ └── presentation
│ │ ├── AndroidApplication.java
│ │ ├── UIThread.java
│ │ ├── exception
│ │ └── ErrorMessageFactory.java
│ │ ├── internal
│ │ └── di
│ │ │ ├── HasComponent.java
│ │ │ ├── PerActivity.java
│ │ │ ├── components
│ │ │ ├── ActivityComponent.java
│ │ │ ├── ApplicationComponent.java
│ │ │ └── UserComponent.java
│ │ │ └── modules
│ │ │ ├── ActivityModule.java
│ │ │ ├── ApplicationModule.java
│ │ │ └── UserModule.java
│ │ ├── mapper
│ │ └── UserModelDataMapper.java
│ │ ├── model
│ │ └── UserModel.java
│ │ ├── navigation
│ │ └── Navigator.java
│ │ ├── presenter
│ │ ├── Presenter.java
│ │ ├── UserDetailsPresenter.java
│ │ └── UserListPresenter.java
│ │ └── view
│ │ ├── LoadDataView.java
│ │ ├── UserDetailsView.java
│ │ ├── UserListView.java
│ │ ├── activity
│ │ ├── BaseActivity.java
│ │ ├── MainActivity.java
│ │ ├── UserDetailsActivity.java
│ │ └── UserListActivity.java
│ │ ├── adapter
│ │ ├── UsersAdapter.java
│ │ └── UsersLayoutManager.java
│ │ ├── component
│ │ └── AutoLoadImageView.java
│ │ └── fragment
│ │ ├── BaseFragment.java
│ │ ├── UserDetailsFragment.java
│ │ └── UserListFragment.java
│ └── res
│ ├── drawable-hdpi
│ ├── ic_launcher.png
│ └── logo.png
│ ├── drawable-mdpi
│ └── ic_launcher.png
│ ├── drawable-xhdpi
│ └── ic_launcher.png
│ ├── drawable-xxhdpi
│ └── ic_launcher.png
│ ├── drawable
│ └── selector_item_user.xml
│ ├── layout
│ ├── activity_layout.xml
│ ├── activity_main.xml
│ ├── fragment_user_details.xml
│ ├── fragment_user_list.xml
│ ├── row_user.xml
│ ├── view_progress.xml
│ ├── view_retry.xml
│ └── view_user_details.xml
│ └── values
│ ├── dimens.xml
│ ├── strings.xml
│ └── styles.xml
└── settings.gradle
/.gitignore:
--------------------------------------------------------------------------------
1 | # Windows thumbnail db
2 | Thumbs.db
3 |
4 | # OSX files
5 | .DS_Store
6 |
7 | # built application files
8 | *.apk
9 | *.ap_
10 |
11 | # files for the dex VM
12 | *.dex
13 |
14 | # Java class files
15 | *.class
16 |
17 | # generated files
18 | bin/
19 | gen/
20 | build/
21 |
22 | # Local configuration file (sdk path, etc)
23 | local.properties
24 |
25 | # Eclipse project files
26 | .classpath
27 | .project
28 |
29 | # Android Studio
30 | .idea
31 | .gradle
32 | /*/local.properties
33 | /*/out
34 | /*/*/build
35 | build
36 | /*/*/production
37 | *.iml
38 | *.iws
39 | *.ipr
40 | *~
41 | *.swp
42 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: android
2 | jdk: oraclejdk8
3 |
4 | android:
5 | components:
6 | - tools
7 | - platform-tools
8 | - tools
9 | - build-tools-27.0.1
10 | - android-26
11 | - extra-google-m2repository
12 | - extra-android-m2repository
13 |
14 | licenses:
15 | - 'android-sdk-preview-license-.+'
16 | - 'android-sdk-license-.+'
17 | - 'google-gdk-license-.+'
18 |
19 | script:
20 | ./gradlew build
21 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | Android-CleanArchitecture
2 | =========================
3 |
4 | ## New version available written in Kotlin:
5 | [Architecting Android… Reloaded](https://fernandocejas.com/2018/05/07/architecting-android-reloaded/)
6 |
7 | Introduction
8 | -----------------
9 | This is a sample app that is part of a blog post I have written about how to architect android application using the Uncle Bob's clean architecture approach.
10 |
11 | [Architecting Android…The clean way?](http://fernandocejas.com/2014/09/03/architecting-android-the-clean-way/)
12 |
13 | [Architecting Android…The evolution](http://fernandocejas.com/2015/07/18/architecting-android-the-evolution/)
14 |
15 | [Tasting Dagger 2 on Android](http://fernandocejas.com/2015/04/11/tasting-dagger-2-on-android/)
16 |
17 | [Clean Architecture…Dynamic Parameters in Use Cases](http://fernandocejas.com/2016/12/24/clean-architecture-dynamic-parameters-in-use-cases/)
18 |
19 | [Demo video of this sample](http://youtu.be/XSjV4sG3ni0)
20 |
21 | Clean architecture
22 | -----------------
23 | 
24 |
25 | Architectural approach
26 | -----------------
27 | 
28 |
29 | Architectural reactive approach
30 | -----------------
31 | 
32 |
33 | Local Development
34 | -----------------
35 |
36 | Here are some useful Gradle/adb commands for executing this example:
37 |
38 | * `./gradlew clean build` - Build the entire example and execute unit and integration tests plus lint check.
39 | * `./gradlew installDebug` - Install the debug apk on the current connected device.
40 | * `./gradlew runUnitTests` - Execute domain and data layer tests (both unit and integration).
41 | * `./gradlew runAcceptanceTests` - Execute espresso and instrumentation acceptance tests.
42 |
43 | Discussions
44 | -----------------
45 |
46 | Refer to the issues section: https://github.com/android10/Android-CleanArchitecture/issues
47 |
48 |
49 | Code style
50 | -----------
51 |
52 | Here you can download and install the java codestyle.
53 | https://github.com/android10/java-code-styles
54 |
55 |
56 | License
57 | --------
58 |
59 | Copyright 2018 Fernando Cejas
60 |
61 | Licensed under the Apache License, Version 2.0 (the "License");
62 | you may not use this file except in compliance with the License.
63 | You may obtain a copy of the License at
64 |
65 | http://www.apache.org/licenses/LICENSE-2.0
66 |
67 | Unless required by applicable law or agreed to in writing, software
68 | distributed under the License is distributed on an "AS IS" BASIS,
69 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
70 | See the License for the specific language governing permissions and
71 | limitations under the License.
72 |
73 |
74 | 
75 |
76 | [](https://android-arsenal.com/details/3/909)
77 |
78 |
79 |
--------------------------------------------------------------------------------
/build.gradle:
--------------------------------------------------------------------------------
1 | apply from: 'buildsystem/ci.gradle'
2 | apply from: 'buildsystem/dependencies.gradle'
3 |
4 | buildscript {
5 | repositories {
6 | jcenter()
7 | mavenCentral()
8 | google()
9 | }
10 | dependencies {
11 | classpath 'com.android.tools.build:gradle:3.0.1'
12 | // classpath 'com.neenbedankt.gradle.plugins:android-apt:1.4'
13 | }
14 | }
15 |
16 | allprojects {
17 | ext {
18 | androidApplicationId = 'com.fernanependocejas.android10.sample.presentation'
19 | androidVersionCode = 1
20 | androidVersionName = "1.0"
21 | testInstrumentationRunner = "android.support.test.runner.AndroidJUnitRunner"
22 | testApplicationId = 'com.fernandocejas.android10.sample.presentation.test'
23 | }
24 | }
25 |
26 | task runDomainUnitTests(dependsOn: [':domain:test']) {
27 | description 'Run unit tests for the domain layer.'
28 | }
29 |
30 | task runDataUnitTests(dependsOn: [':data:cleanTestDebugUnitTest', ':data:testDebugUnitTest']) {
31 | description 'Run unit tests for the data layer.'
32 | }
33 |
34 | task runUnitTests(dependsOn: ['runDomainUnitTests', 'runDataUnitTests']) {
35 | description 'Run unit tests for both domain and data layers.'
36 | }
37 |
38 | task runAcceptanceTests(dependsOn: [':presentation:connectedAndroidTest']) {
39 | description 'Run application acceptance tests.'
40 | }
41 |
42 |
--------------------------------------------------------------------------------
/buildsystem/ci.gradle:
--------------------------------------------------------------------------------
1 | def ciServer = 'TRAVIS'
2 | def executingOnCI = "true".equals(System.getenv(ciServer))
3 |
4 | // Since for CI we always do full clean builds, we don't want to pre-dex
5 | // See http://tools.android.com/tech-docs/new-build-system/tips
6 | subprojects {
7 | project.plugins.whenPluginAdded { plugin ->
8 | if ('com.android.build.gradle.AppPlugin'.equals(plugin.class.name) ||
9 | 'com.android.build.gradle.LibraryPlugin'.equals(plugin.class.name)) {
10 | project.android.dexOptions.preDexLibraries = !executingOnCI
11 | }
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/buildsystem/debug.keystore:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/android10/Android-CleanArchitecture/8ed4222c537e40db05e9e685bbc253fafb6b8e1f/buildsystem/debug.keystore
--------------------------------------------------------------------------------
/buildsystem/dependencies.gradle:
--------------------------------------------------------------------------------
1 | allprojects {
2 | repositories {
3 | jcenter()
4 | }
5 | }
6 |
7 | ext {
8 | //Android
9 | androidBuildToolsVersion = "27.0.1"
10 | androidMinSdkVersion = 15
11 | androidTargetSdkVersion = 26
12 | androidCompileSdkVersion = 26
13 |
14 | //Libraries
15 | daggerVersion = '2.8'
16 | butterKnifeVersion = '7.0.1'
17 | recyclerViewVersion = '25.4.0'
18 | rxJavaVersion = '2.0.2'
19 | rxAndroidVersion = '2.0.1'
20 | javaxAnnotationVersion = '1.0'
21 | javaxInjectVersion = '1'
22 | gsonVersion = '2.3'
23 | okHttpVersion = '2.5.0'
24 | androidAnnotationsVersion = '25.4.0'
25 | arrowVersion = '1.0.0'
26 |
27 | //Testing
28 | robolectricVersion = '3.1.1'
29 | jUnitVersion = '4.12'
30 | assertJVersion = '1.7.1'
31 | mockitoVersion = '1.9.5'
32 | dexmakerVersion = '1.0'
33 | espressoVersion = '3.0.1'
34 | testingSupportLibVersion = '0.1'
35 |
36 | //Development
37 | leakCanaryVersion = '1.3.1'
38 |
39 | presentationDependencies = [
40 | daggerCompiler: "com.google.dagger:dagger-compiler:${daggerVersion}",
41 | dagger: "com.google.dagger:dagger:${daggerVersion}",
42 | butterKnife: "com.jakewharton:butterknife:${butterKnifeVersion}",
43 | recyclerView: "com.android.support:recyclerview-v7:${recyclerViewVersion}",
44 | rxJava: "io.reactivex.rxjava2:rxjava:${rxJavaVersion}",
45 | rxAndroid: "io.reactivex.rxjava2:rxandroid:${rxAndroidVersion}",
46 | javaxAnnotation: "javax.annotation:jsr250-api:${javaxAnnotationVersion}"
47 | ]
48 |
49 | presentationTestDependencies = [
50 | mockito: "org.mockito:mockito-core:${mockitoVersion}",
51 | dexmaker: "com.google.dexmaker:dexmaker:${dexmakerVersion}",
52 | dexmakerMockito: "com.google.dexmaker:dexmaker-mockito:${dexmakerVersion}",
53 | espresso: "com.android.support.test.espresso:espresso-core:${espressoVersion}",
54 | testingSupportLib: "com.android.support.test:testing-support-lib:${testingSupportLibVersion}",
55 | ]
56 |
57 | domainDependencies = [
58 | javaxAnnotation: "javax.annotation:jsr250-api:${javaxAnnotationVersion}",
59 | javaxInject: "javax.inject:javax.inject:${javaxInjectVersion}",
60 | rxJava: "io.reactivex.rxjava2:rxjava:${rxJavaVersion}",
61 | arrow: "com.fernandocejas:arrow:${arrowVersion}"
62 | ]
63 |
64 | domainTestDependencies = [
65 | junit: "junit:junit:${jUnitVersion}",
66 | mockito: "org.mockito:mockito-core:${mockitoVersion}",
67 | assertj: "org.assertj:assertj-core:${assertJVersion}"
68 | ]
69 |
70 | dataDependencies = [
71 | daggerCompiler: "com.google.dagger:dagger-compiler:${daggerVersion}",
72 | dagger: "com.google.dagger:dagger:${daggerVersion}",
73 | okHttp: "com.squareup.okhttp:okhttp:${okHttpVersion}",
74 | gson: "com.google.code.gson:gson:${gsonVersion}",
75 | rxJava: "io.reactivex.rxjava2:rxjava:${rxJavaVersion}",
76 | rxAndroid: "io.reactivex.rxjava2:rxandroid:${rxAndroidVersion}",
77 | javaxAnnotation: "javax.annotation:jsr250-api:${javaxAnnotationVersion}",
78 | javaxInject: "javax.inject:javax.inject:${javaxInjectVersion}",
79 | androidAnnotations: "com.android.support:support-annotations:${androidAnnotationsVersion}"
80 | ]
81 |
82 | dataTestDependencies = [
83 | junit: "junit:junit:${jUnitVersion}",
84 | assertj: "org.assertj:assertj-core:${assertJVersion}",
85 | mockito: "org.mockito:mockito-core:${mockitoVersion}",
86 | robolectric: "org.robolectric:robolectric:${robolectricVersion}",
87 | ]
88 |
89 | developmentDependencies = [
90 | leakCanary: "com.squareup.leakcanary:leakcanary-android:${leakCanaryVersion}",
91 | ]
92 | }
93 |
--------------------------------------------------------------------------------
/data/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/data/build.gradle:
--------------------------------------------------------------------------------
1 | buildscript {
2 | repositories {
3 | mavenCentral()
4 | }
5 | dependencies {
6 | classpath 'me.tatarka:gradle-retrolambda:3.7.0'
7 | }
8 | }
9 |
10 | apply plugin: 'com.android.library'
11 | //apply plugin: 'com.neenbedankt.android-apt'
12 | apply plugin: 'me.tatarka.retrolambda'
13 |
14 | android {
15 | defaultPublishConfig "debug"
16 |
17 | def globalConfiguration = rootProject.extensions.getByName("ext")
18 |
19 | compileSdkVersion globalConfiguration.getAt("androidCompileSdkVersion")
20 | buildToolsVersion globalConfiguration.getAt("androidBuildToolsVersion")
21 |
22 | defaultConfig {
23 | minSdkVersion globalConfiguration.getAt("androidMinSdkVersion")
24 | targetSdkVersion globalConfiguration.getAt("androidTargetSdkVersion")
25 | versionCode globalConfiguration.getAt("androidVersionCode")
26 | }
27 |
28 | compileOptions {
29 | sourceCompatibility JavaVersion.VERSION_1_8
30 | targetCompatibility JavaVersion.VERSION_1_8
31 | }
32 |
33 | packagingOptions {
34 | exclude 'LICENSE.txt'
35 | exclude 'META-INF/DEPENDENCIES'
36 | exclude 'META-INF/ASL2.0'
37 | exclude 'META-INF/NOTICE'
38 | exclude 'META-INF/LICENSE'
39 | }
40 |
41 | lintOptions {
42 | quiet true
43 | abortOnError false
44 | ignoreWarnings true
45 | disable 'InvalidPackage' // Some libraries have issues with this
46 | disable 'OldTargetApi' // Due to Robolectric that modifies the manifest when running tests
47 | }
48 | }
49 |
50 | dependencies {
51 | def dataDependencies = rootProject.ext.dataDependencies
52 | def testDependencies = rootProject.ext.dataTestDependencies
53 |
54 | implementation project(':domain')
55 | compileOnly dataDependencies.javaxAnnotation
56 | implementation dataDependencies.javaxInject
57 | implementation dataDependencies.okHttp
58 | implementation dataDependencies.gson
59 | implementation dataDependencies.rxJava
60 | implementation dataDependencies.rxAndroid
61 | implementation dataDependencies.androidAnnotations
62 |
63 | testImplementation testDependencies.junit
64 | testImplementation testDependencies.assertj
65 | testImplementation testDependencies.mockito
66 | testImplementation testDependencies.robolectric
67 | }
68 |
69 | repositories {
70 | google()
71 | }
--------------------------------------------------------------------------------
/data/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # By default, the flags in this file are appended to flags specified
3 | # in /Users/fcejas/Software/SDKs/android-sdk/tools/proguard/proguard-android.txt
4 | # You can edit the include path and order by changing the proguardFiles
5 | # directive in build.gradle.
6 | #
7 | # For more details, see
8 | # http://developer.android.com/guide/developing/tools/proguard.html
9 |
10 | # Add any project specific keep options here:
11 |
12 | # If your project uses WebView with JS, uncomment the following
13 | # and specify the fully qualified class name to the JavaScript interface
14 | # class:
15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
16 | # public *;
17 | #}
18 |
--------------------------------------------------------------------------------
/data/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/data/src/main/java/com/fernandocejas/android10/sample/data/cache/FileManager.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (C) 2015 Fernando Cejas Open Source Project
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.fernandocejas.android10.sample.data.cache;
17 |
18 | import android.content.Context;
19 | import android.content.SharedPreferences;
20 | import java.io.BufferedReader;
21 | import java.io.File;
22 | import java.io.FileReader;
23 | import java.io.FileWriter;
24 | import java.io.IOException;
25 | import javax.inject.Inject;
26 | import javax.inject.Singleton;
27 |
28 | /**
29 | * Helper class to do operations on regular files/directories.
30 | */
31 | @Singleton
32 | public class FileManager {
33 |
34 | @Inject
35 | FileManager() {}
36 |
37 | /**
38 | * Writes a file to Disk.
39 | * This is an I/O operation and this method executes in the main thread, so it is recommended to
40 | * perform this operation using another thread.
41 | *
42 | * @param file The file to write to Disk.
43 | */
44 | void writeToFile(File file, String fileContent) {
45 | if (!file.exists()) {
46 | try {
47 | final FileWriter writer = new FileWriter(file);
48 | writer.write(fileContent);
49 | writer.close();
50 | } catch (IOException e) {
51 | e.printStackTrace();
52 | }
53 | }
54 | }
55 |
56 | /**
57 | * Reads a content from a file.
58 | * This is an I/O operation and this method executes in the main thread, so it is recommended to
59 | * perform the operation using another thread.
60 | *
61 | * @param file The file to read from.
62 | * @return A string with the content of the file.
63 | */
64 | String readFileContent(File file) {
65 | final StringBuilder fileContentBuilder = new StringBuilder();
66 | if (file.exists()) {
67 | String stringLine;
68 | try {
69 | final FileReader fileReader = new FileReader(file);
70 | final BufferedReader bufferedReader = new BufferedReader(fileReader);
71 | while ((stringLine = bufferedReader.readLine()) != null) {
72 | fileContentBuilder.append(stringLine).append("\n");
73 | }
74 | bufferedReader.close();
75 | fileReader.close();
76 | } catch (IOException e) {
77 | e.printStackTrace();
78 | }
79 | }
80 | return fileContentBuilder.toString();
81 | }
82 |
83 | /**
84 | * Returns a boolean indicating whether this file can be found on the underlying file system.
85 | *
86 | * @param file The file to check existence.
87 | * @return true if this file exists, false otherwise.
88 | */
89 | boolean exists(File file) {
90 | return file.exists();
91 | }
92 |
93 | /**
94 | * Warning: Deletes the content of a directory.
95 | * This is an I/O operation and this method executes in the main thread, so it is recommended to
96 | * perform the operation using another thread.
97 | *
98 | * @param directory The directory which its content will be deleted.
99 | */
100 | boolean clearDirectory(File directory) {
101 | boolean result = false;
102 | if (directory.exists()) {
103 | for (File file : directory.listFiles()) {
104 | result = file.delete();
105 | }
106 | }
107 | return result;
108 | }
109 |
110 | /**
111 | * Write a value to a user preferences file.
112 | *
113 | * @param context {@link android.content.Context} to retrieve android user preferences.
114 | * @param preferenceFileName A file name reprensenting where data will be written to.
115 | * @param key A string for the key that will be used to retrieve the value in the future.
116 | * @param value A long representing the value to be inserted.
117 | */
118 | void writeToPreferences(Context context, String preferenceFileName, String key,
119 | long value) {
120 |
121 | final SharedPreferences sharedPreferences = context.getSharedPreferences(preferenceFileName,
122 | Context.MODE_PRIVATE);
123 | final SharedPreferences.Editor editor = sharedPreferences.edit();
124 | editor.putLong(key, value);
125 | editor.apply();
126 | }
127 |
128 | /**
129 | * Get a value from a user preferences file.
130 | *
131 | * @param context {@link android.content.Context} to retrieve android user preferences.
132 | * @param preferenceFileName A file name representing where data will be get from.
133 | * @param key A key that will be used to retrieve the value from the preference file.
134 | * @return A long representing the value retrieved from the preferences file.
135 | */
136 | long getFromPreferences(Context context, String preferenceFileName, String key) {
137 | final SharedPreferences sharedPreferences = context.getSharedPreferences(preferenceFileName,
138 | Context.MODE_PRIVATE);
139 | return sharedPreferences.getLong(key, 0);
140 | }
141 | }
142 |
--------------------------------------------------------------------------------
/data/src/main/java/com/fernandocejas/android10/sample/data/cache/UserCache.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (C) 2015 Fernando Cejas Open Source Project
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.fernandocejas.android10.sample.data.cache;
17 |
18 | import com.fernandocejas.android10.sample.data.entity.UserEntity;
19 | import io.reactivex.Observable;
20 |
21 | /**
22 | * An interface representing a user Cache.
23 | */
24 | public interface UserCache {
25 | /**
26 | * Gets an {@link Observable} which will emit a {@link UserEntity}.
27 | *
28 | * @param userId The user id to retrieve data.
29 | */
30 | Observable get(final int userId);
31 |
32 | /**
33 | * Puts and element into the cache.
34 | *
35 | * @param userEntity Element to insert in the cache.
36 | */
37 | void put(UserEntity userEntity);
38 |
39 | /**
40 | * Checks if an element (User) exists in the cache.
41 | *
42 | * @param userId The id used to look for inside the cache.
43 | * @return true if the element is cached, otherwise false.
44 | */
45 | boolean isCached(final int userId);
46 |
47 | /**
48 | * Checks if the cache is expired.
49 | *
50 | * @return true, the cache is expired, otherwise false.
51 | */
52 | boolean isExpired();
53 |
54 | /**
55 | * Evict all elements of the cache.
56 | */
57 | void evictAll();
58 | }
59 |
--------------------------------------------------------------------------------
/data/src/main/java/com/fernandocejas/android10/sample/data/cache/serializer/Serializer.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (C) 2015 Fernando Cejas Open Source Project
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.fernandocejas.android10.sample.data.cache.serializer;
17 |
18 | import com.google.gson.Gson;
19 | import javax.inject.Inject;
20 | import javax.inject.Singleton;
21 |
22 | /**
23 | * Json Serializer/Deserializer.
24 | */
25 | @Singleton
26 | public class Serializer {
27 |
28 | private final Gson gson = new Gson();
29 |
30 | @Inject Serializer() {}
31 |
32 | /**
33 | * Serialize an object to Json.
34 | *
35 | * @param object to serialize.
36 | */
37 | public String serialize(Object object, Class clazz) {
38 | return gson.toJson(object, clazz);
39 | }
40 |
41 | /**
42 | * Deserialize a json representation of an object.
43 | *
44 | * @param string A json string to deserialize.
45 | */
46 | public T deserialize(String string, Class clazz) {
47 | return gson.fromJson(string, clazz);
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/data/src/main/java/com/fernandocejas/android10/sample/data/entity/UserEntity.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (C) 2015 Fernando Cejas Open Source Project
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.fernandocejas.android10.sample.data.entity;
17 |
18 | import com.google.gson.annotations.SerializedName;
19 |
20 | /**
21 | * User Entity used in the data layer.
22 | */
23 | public class UserEntity {
24 |
25 | @SerializedName("id")
26 | private int userId;
27 |
28 | @SerializedName("cover_url")
29 | private String coverUrl;
30 |
31 | @SerializedName("full_name")
32 | private String fullname;
33 |
34 | @SerializedName("description")
35 | private String description;
36 |
37 | @SerializedName("followers")
38 | private int followers;
39 |
40 | @SerializedName("email")
41 | private String email;
42 |
43 | public UserEntity() {
44 | //empty
45 | }
46 |
47 | public int getUserId() {
48 | return userId;
49 | }
50 |
51 | public void setUserId(int userId) {
52 | this.userId = userId;
53 | }
54 |
55 | public String getCoverUrl() {
56 | return coverUrl;
57 | }
58 |
59 | public String getFullname() {
60 | return fullname;
61 | }
62 |
63 | public void setFullname(String fullname) {
64 | this.fullname = fullname;
65 | }
66 |
67 | public String getDescription() {
68 | return description;
69 | }
70 |
71 | public int getFollowers() {
72 | return followers;
73 | }
74 |
75 | public String getEmail() {
76 | return email;
77 | }
78 | }
79 |
--------------------------------------------------------------------------------
/data/src/main/java/com/fernandocejas/android10/sample/data/entity/mapper/UserEntityDataMapper.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (C) 2015 Fernando Cejas Open Source Project
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.fernandocejas.android10.sample.data.entity.mapper;
17 |
18 | import com.fernandocejas.android10.sample.data.entity.UserEntity;
19 | import com.fernandocejas.android10.sample.domain.User;
20 | import java.util.ArrayList;
21 | import java.util.Collection;
22 | import java.util.List;
23 | import javax.inject.Inject;
24 | import javax.inject.Singleton;
25 |
26 | /**
27 | * Mapper class used to transform {@link UserEntity} (in the data layer) to {@link User} in the
28 | * domain layer.
29 | */
30 | @Singleton
31 | public class UserEntityDataMapper {
32 |
33 | @Inject
34 | UserEntityDataMapper() {}
35 |
36 | /**
37 | * Transform a {@link UserEntity} into an {@link User}.
38 | *
39 | * @param userEntity Object to be transformed.
40 | * @return {@link User} if valid {@link UserEntity} otherwise null.
41 | */
42 | public User transform(UserEntity userEntity) {
43 | User user = null;
44 | if (userEntity != null) {
45 | user = new User(userEntity.getUserId());
46 | user.setCoverUrl(userEntity.getCoverUrl());
47 | user.setFullName(userEntity.getFullname());
48 | user.setDescription(userEntity.getDescription());
49 | user.setFollowers(userEntity.getFollowers());
50 | user.setEmail(userEntity.getEmail());
51 | }
52 | return user;
53 | }
54 |
55 | /**
56 | * Transform a List of {@link UserEntity} into a Collection of {@link User}.
57 | *
58 | * @param userEntityCollection Object Collection to be transformed.
59 | * @return {@link User} if valid {@link UserEntity} otherwise null.
60 | */
61 | public List transform(Collection userEntityCollection) {
62 | final List userList = new ArrayList<>(20);
63 | for (UserEntity userEntity : userEntityCollection) {
64 | final User user = transform(userEntity);
65 | if (user != null) {
66 | userList.add(user);
67 | }
68 | }
69 | return userList;
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/data/src/main/java/com/fernandocejas/android10/sample/data/entity/mapper/UserEntityJsonMapper.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (C) 2015 Fernando Cejas Open Source Project
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.fernandocejas.android10.sample.data.entity.mapper;
17 |
18 | import com.fernandocejas.android10.sample.data.entity.UserEntity;
19 | import com.google.gson.Gson;
20 | import com.google.gson.JsonSyntaxException;
21 | import com.google.gson.reflect.TypeToken;
22 | import java.lang.reflect.Type;
23 | import java.util.List;
24 | import javax.inject.Inject;
25 |
26 | /**
27 | * Class used to transform from Strings representing json to valid objects.
28 | */
29 | public class UserEntityJsonMapper {
30 |
31 | private final Gson gson;
32 |
33 | @Inject
34 | public UserEntityJsonMapper() {
35 | this.gson = new Gson();
36 | }
37 |
38 | /**
39 | * Transform from valid json string to {@link UserEntity}.
40 | *
41 | * @param userJsonResponse A json representing a user profile.
42 | * @return {@link UserEntity}.
43 | * @throws com.google.gson.JsonSyntaxException if the json string is not a valid json structure.
44 | */
45 | public UserEntity transformUserEntity(String userJsonResponse) throws JsonSyntaxException {
46 | final Type userEntityType = new TypeToken() {}.getType();
47 | return this.gson.fromJson(userJsonResponse, userEntityType);
48 | }
49 |
50 | /**
51 | * Transform from valid json string to List of {@link UserEntity}.
52 | *
53 | * @param userListJsonResponse A json representing a collection of users.
54 | * @return List of {@link UserEntity}.
55 | * @throws com.google.gson.JsonSyntaxException if the json string is not a valid json structure.
56 | */
57 | public List transformUserEntityCollection(String userListJsonResponse)
58 | throws JsonSyntaxException {
59 | final Type listOfUserEntityType = new TypeToken>() {}.getType();
60 | return this.gson.fromJson(userListJsonResponse, listOfUserEntityType);
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/data/src/main/java/com/fernandocejas/android10/sample/data/exception/NetworkConnectionException.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (C) 2015 Fernando Cejas Open Source Project
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.fernandocejas.android10.sample.data.exception;
17 |
18 | /**
19 | * Exception throw by the application when a there is a network connection exception.
20 | */
21 | public class NetworkConnectionException extends Exception {
22 |
23 | public NetworkConnectionException() {
24 | super();
25 | }
26 |
27 | public NetworkConnectionException(final Throwable cause) {
28 | super(cause);
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/data/src/main/java/com/fernandocejas/android10/sample/data/exception/RepositoryErrorBundle.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (C) 2015 Fernando Cejas Open Source Project
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.fernandocejas.android10.sample.data.exception;
17 |
18 | import com.fernandocejas.android10.sample.domain.exception.ErrorBundle;
19 |
20 | /**
21 | * Wrapper around Exceptions used to manage errors in the repository.
22 | */
23 | class RepositoryErrorBundle implements ErrorBundle {
24 |
25 | private final Exception exception;
26 |
27 | RepositoryErrorBundle(Exception exception) {
28 | this.exception = exception;
29 | }
30 |
31 | @Override
32 | public Exception getException() {
33 | return exception;
34 | }
35 |
36 | @Override
37 | public String getErrorMessage() {
38 | String message = "";
39 | if (this.exception != null) {
40 | message = this.exception.getMessage();
41 | }
42 | return message;
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/data/src/main/java/com/fernandocejas/android10/sample/data/exception/UserNotFoundException.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (C) 2015 Fernando Cejas Open Source Project
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.fernandocejas.android10.sample.data.exception;
17 |
18 | /**
19 | * Exception throw by the application when a User search can't return a valid result.
20 | */
21 | public class UserNotFoundException extends Exception {
22 | public UserNotFoundException() {
23 | super();
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/data/src/main/java/com/fernandocejas/android10/sample/data/executor/JobExecutor.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (C) 2015 Fernando Cejas Open Source Project
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.fernandocejas.android10.sample.data.executor;
17 |
18 | import android.support.annotation.NonNull;
19 | import com.fernandocejas.android10.sample.domain.executor.ThreadExecutor;
20 | import java.util.concurrent.LinkedBlockingQueue;
21 | import java.util.concurrent.ThreadFactory;
22 | import java.util.concurrent.ThreadPoolExecutor;
23 | import java.util.concurrent.TimeUnit;
24 | import javax.inject.Inject;
25 | import javax.inject.Singleton;
26 |
27 | /**
28 | * Decorated {@link java.util.concurrent.ThreadPoolExecutor}
29 | */
30 | @Singleton
31 | public class JobExecutor implements ThreadExecutor {
32 | private final ThreadPoolExecutor threadPoolExecutor;
33 |
34 | @Inject
35 | JobExecutor() {
36 | this.threadPoolExecutor = new ThreadPoolExecutor(3, 5, 10, TimeUnit.SECONDS,
37 | new LinkedBlockingQueue<>(), new JobThreadFactory());
38 | }
39 |
40 | @Override public void execute(@NonNull Runnable runnable) {
41 | this.threadPoolExecutor.execute(runnable);
42 | }
43 |
44 | private static class JobThreadFactory implements ThreadFactory {
45 | private int counter = 0;
46 |
47 | @Override public Thread newThread(@NonNull Runnable runnable) {
48 | return new Thread(runnable, "android_" + counter++);
49 | }
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/data/src/main/java/com/fernandocejas/android10/sample/data/net/ApiConnection.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (C) 2015 Fernando Cejas Open Source Project
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.fernandocejas.android10.sample.data.net;
17 |
18 | import android.support.annotation.Nullable;
19 | import com.squareup.okhttp.OkHttpClient;
20 | import com.squareup.okhttp.Request;
21 | import java.io.IOException;
22 | import java.net.MalformedURLException;
23 | import java.net.URL;
24 | import java.util.concurrent.Callable;
25 | import java.util.concurrent.TimeUnit;
26 |
27 | /**
28 | * Api Connection class used to retrieve data from the cloud.
29 | * Implements {@link java.util.concurrent.Callable} so when executed asynchronously can
30 | * return a value.
31 | */
32 | class ApiConnection implements Callable {
33 |
34 | private static final String CONTENT_TYPE_LABEL = "Content-Type";
35 | private static final String CONTENT_TYPE_VALUE_JSON = "application/json; charset=utf-8";
36 |
37 | private URL url;
38 | private String response;
39 |
40 | private ApiConnection(String url) throws MalformedURLException {
41 | this.url = new URL(url);
42 | }
43 |
44 | static ApiConnection createGET(String url) throws MalformedURLException {
45 | return new ApiConnection(url);
46 | }
47 |
48 | /**
49 | * Do a request to an api synchronously.
50 | * It should not be executed in the main thread of the application.
51 | *
52 | * @return A string response
53 | */
54 | @Nullable
55 | String requestSyncCall() {
56 | connectToApi();
57 | return response;
58 | }
59 |
60 | private void connectToApi() {
61 | OkHttpClient okHttpClient = this.createClient();
62 | final Request request = new Request.Builder()
63 | .url(this.url)
64 | .addHeader(CONTENT_TYPE_LABEL, CONTENT_TYPE_VALUE_JSON)
65 | .get()
66 | .build();
67 |
68 | try {
69 | this.response = okHttpClient.newCall(request).execute().body().string();
70 | } catch (IOException e) {
71 | e.printStackTrace();
72 | }
73 | }
74 |
75 | private OkHttpClient createClient() {
76 | final OkHttpClient okHttpClient = new OkHttpClient();
77 | okHttpClient.setReadTimeout(10000, TimeUnit.MILLISECONDS);
78 | okHttpClient.setConnectTimeout(15000, TimeUnit.MILLISECONDS);
79 |
80 | return okHttpClient;
81 | }
82 |
83 | @Override public String call() throws Exception {
84 | return requestSyncCall();
85 | }
86 | }
87 |
--------------------------------------------------------------------------------
/data/src/main/java/com/fernandocejas/android10/sample/data/net/RestApi.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (C) 2015 Fernando Cejas Open Source Project
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.fernandocejas.android10.sample.data.net;
17 |
18 | import com.fernandocejas.android10.sample.data.entity.UserEntity;
19 | import io.reactivex.Observable;
20 | import java.util.List;
21 |
22 | /**
23 | * RestApi for retrieving data from the network.
24 | */
25 | public interface RestApi {
26 | String API_BASE_URL =
27 | "https://raw.githubusercontent.com/android10/Sample-Data/master/Android-CleanArchitecture/";
28 |
29 | /** Api url for getting all users */
30 | String API_URL_GET_USER_LIST = API_BASE_URL + "users.json";
31 | /** Api url for getting a user profile: Remember to concatenate id + 'json' */
32 | String API_URL_GET_USER_DETAILS = API_BASE_URL + "user_";
33 |
34 | /**
35 | * Retrieves an {@link Observable} which will emit a List of {@link UserEntity}.
36 | */
37 | Observable> userEntityList();
38 |
39 | /**
40 | * Retrieves an {@link Observable} which will emit a {@link UserEntity}.
41 | *
42 | * @param userId The user id used to get user data.
43 | */
44 | Observable userEntityById(final int userId);
45 | }
46 |
--------------------------------------------------------------------------------
/data/src/main/java/com/fernandocejas/android10/sample/data/net/RestApiImpl.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (C) 2015 Fernando Cejas Open Source Project
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.fernandocejas.android10.sample.data.net;
17 |
18 | import android.content.Context;
19 | import android.net.ConnectivityManager;
20 | import android.net.NetworkInfo;
21 | import com.fernandocejas.android10.sample.data.entity.UserEntity;
22 | import com.fernandocejas.android10.sample.data.entity.mapper.UserEntityJsonMapper;
23 | import com.fernandocejas.android10.sample.data.exception.NetworkConnectionException;
24 | import io.reactivex.Observable;
25 | import java.net.MalformedURLException;
26 | import java.util.List;
27 |
28 | /**
29 | * {@link RestApi} implementation for retrieving data from the network.
30 | */
31 | public class RestApiImpl implements RestApi {
32 |
33 | private final Context context;
34 | private final UserEntityJsonMapper userEntityJsonMapper;
35 |
36 | /**
37 | * Constructor of the class
38 | *
39 | * @param context {@link android.content.Context}.
40 | * @param userEntityJsonMapper {@link UserEntityJsonMapper}.
41 | */
42 | public RestApiImpl(Context context, UserEntityJsonMapper userEntityJsonMapper) {
43 | if (context == null || userEntityJsonMapper == null) {
44 | throw new IllegalArgumentException("The constructor parameters cannot be null!!!");
45 | }
46 | this.context = context.getApplicationContext();
47 | this.userEntityJsonMapper = userEntityJsonMapper;
48 | }
49 |
50 | @Override public Observable> userEntityList() {
51 | return Observable.create(emitter -> {
52 | if (isThereInternetConnection()) {
53 | try {
54 | String responseUserEntities = getUserEntitiesFromApi();
55 | if (responseUserEntities != null) {
56 | emitter.onNext(userEntityJsonMapper.transformUserEntityCollection(
57 | responseUserEntities));
58 | emitter.onComplete();
59 | } else {
60 | emitter.onError(new NetworkConnectionException());
61 | }
62 | } catch (Exception e) {
63 | emitter.onError(new NetworkConnectionException(e.getCause()));
64 | }
65 | } else {
66 | emitter.onError(new NetworkConnectionException());
67 | }
68 | });
69 | }
70 |
71 | @Override public Observable userEntityById(final int userId) {
72 | return Observable.create(emitter -> {
73 | if (isThereInternetConnection()) {
74 | try {
75 | String responseUserDetails = getUserDetailsFromApi(userId);
76 | if (responseUserDetails != null) {
77 | emitter.onNext(userEntityJsonMapper.transformUserEntity(responseUserDetails));
78 | emitter.onComplete();
79 | } else {
80 | emitter.onError(new NetworkConnectionException());
81 | }
82 | } catch (Exception e) {
83 | emitter.onError(new NetworkConnectionException(e.getCause()));
84 | }
85 | } else {
86 | emitter.onError(new NetworkConnectionException());
87 | }
88 | });
89 | }
90 |
91 | private String getUserEntitiesFromApi() throws MalformedURLException {
92 | return ApiConnection.createGET(API_URL_GET_USER_LIST).requestSyncCall();
93 | }
94 |
95 | private String getUserDetailsFromApi(int userId) throws MalformedURLException {
96 | String apiUrl = API_URL_GET_USER_DETAILS + userId + ".json";
97 | return ApiConnection.createGET(apiUrl).requestSyncCall();
98 | }
99 |
100 | /**
101 | * Checks if the device has any active internet connection.
102 | *
103 | * @return true device with internet connection, otherwise false.
104 | */
105 | private boolean isThereInternetConnection() {
106 | boolean isConnected;
107 |
108 | ConnectivityManager connectivityManager =
109 | (ConnectivityManager) this.context.getSystemService(Context.CONNECTIVITY_SERVICE);
110 | NetworkInfo networkInfo = connectivityManager.getActiveNetworkInfo();
111 | isConnected = (networkInfo != null && networkInfo.isConnectedOrConnecting());
112 |
113 | return isConnected;
114 | }
115 | }
116 |
--------------------------------------------------------------------------------
/data/src/main/java/com/fernandocejas/android10/sample/data/repository/UserDataRepository.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (C) 2015 Fernando Cejas Open Source Project
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.fernandocejas.android10.sample.data.repository;
17 |
18 | import com.fernandocejas.android10.sample.data.entity.mapper.UserEntityDataMapper;
19 | import com.fernandocejas.android10.sample.data.repository.datasource.UserDataStore;
20 | import com.fernandocejas.android10.sample.data.repository.datasource.UserDataStoreFactory;
21 | import com.fernandocejas.android10.sample.domain.User;
22 | import com.fernandocejas.android10.sample.domain.repository.UserRepository;
23 | import io.reactivex.Observable;
24 | import java.util.List;
25 | import javax.inject.Inject;
26 | import javax.inject.Singleton;
27 |
28 | /**
29 | * {@link UserRepository} for retrieving user data.
30 | */
31 | @Singleton
32 | public class UserDataRepository implements UserRepository {
33 |
34 | private final UserDataStoreFactory userDataStoreFactory;
35 | private final UserEntityDataMapper userEntityDataMapper;
36 |
37 | /**
38 | * Constructs a {@link UserRepository}.
39 | *
40 | * @param dataStoreFactory A factory to construct different data source implementations.
41 | * @param userEntityDataMapper {@link UserEntityDataMapper}.
42 | */
43 | @Inject
44 | UserDataRepository(UserDataStoreFactory dataStoreFactory,
45 | UserEntityDataMapper userEntityDataMapper) {
46 | this.userDataStoreFactory = dataStoreFactory;
47 | this.userEntityDataMapper = userEntityDataMapper;
48 | }
49 |
50 | @Override public Observable> users() {
51 | //we always get all users from the cloud
52 | final UserDataStore userDataStore = this.userDataStoreFactory.createCloudDataStore();
53 | return userDataStore.userEntityList().map(this.userEntityDataMapper::transform);
54 | }
55 |
56 | @Override public Observable user(int userId) {
57 | final UserDataStore userDataStore = this.userDataStoreFactory.create(userId);
58 | return userDataStore.userEntityDetails(userId).map(this.userEntityDataMapper::transform);
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/data/src/main/java/com/fernandocejas/android10/sample/data/repository/datasource/CloudUserDataStore.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (C) 2015 Fernando Cejas Open Source Project
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.fernandocejas.android10.sample.data.repository.datasource;
17 |
18 | import com.fernandocejas.android10.sample.data.cache.UserCache;
19 | import com.fernandocejas.android10.sample.data.entity.UserEntity;
20 | import com.fernandocejas.android10.sample.data.net.RestApi;
21 | import io.reactivex.Observable;
22 | import java.util.List;
23 |
24 | /**
25 | * {@link UserDataStore} implementation based on connections to the api (Cloud).
26 | */
27 | class CloudUserDataStore implements UserDataStore {
28 |
29 | private final RestApi restApi;
30 | private final UserCache userCache;
31 |
32 | /**
33 | * Construct a {@link UserDataStore} based on connections to the api (Cloud).
34 | *
35 | * @param restApi The {@link RestApi} implementation to use.
36 | * @param userCache A {@link UserCache} to cache data retrieved from the api.
37 | */
38 | CloudUserDataStore(RestApi restApi, UserCache userCache) {
39 | this.restApi = restApi;
40 | this.userCache = userCache;
41 | }
42 |
43 | @Override public Observable> userEntityList() {
44 | return this.restApi.userEntityList();
45 | }
46 |
47 | @Override public Observable userEntityDetails(final int userId) {
48 | return this.restApi.userEntityById(userId).doOnNext(CloudUserDataStore.this.userCache::put);
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/data/src/main/java/com/fernandocejas/android10/sample/data/repository/datasource/DiskUserDataStore.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (C) 2015 Fernando Cejas Open Source Project
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.fernandocejas.android10.sample.data.repository.datasource;
17 |
18 | import com.fernandocejas.android10.sample.data.cache.UserCache;
19 | import com.fernandocejas.android10.sample.data.entity.UserEntity;
20 | import io.reactivex.Observable;
21 | import java.util.List;
22 |
23 | /**
24 | * {@link UserDataStore} implementation based on file system data store.
25 | */
26 | class DiskUserDataStore implements UserDataStore {
27 |
28 | private final UserCache userCache;
29 |
30 | /**
31 | * Construct a {@link UserDataStore} based file system data store.
32 | *
33 | * @param userCache A {@link UserCache} to cache data retrieved from the api.
34 | */
35 | DiskUserDataStore(UserCache userCache) {
36 | this.userCache = userCache;
37 | }
38 |
39 | @Override public Observable> userEntityList() {
40 | //TODO: implement simple cache for storing/retrieving collections of users.
41 | throw new UnsupportedOperationException("Operation is not available!!!");
42 | }
43 |
44 | @Override public Observable userEntityDetails(final int userId) {
45 | return this.userCache.get(userId);
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/data/src/main/java/com/fernandocejas/android10/sample/data/repository/datasource/UserDataStore.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (C) 2015 Fernando Cejas Open Source Project
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.fernandocejas.android10.sample.data.repository.datasource;
17 |
18 | import com.fernandocejas.android10.sample.data.entity.UserEntity;
19 | import io.reactivex.Observable;
20 | import java.util.List;
21 |
22 | /**
23 | * Interface that represents a data store from where data is retrieved.
24 | */
25 | public interface UserDataStore {
26 | /**
27 | * Get an {@link Observable} which will emit a List of {@link UserEntity}.
28 | */
29 | Observable> userEntityList();
30 |
31 | /**
32 | * Get an {@link Observable} which will emit a {@link UserEntity} by its id.
33 | *
34 | * @param userId The id to retrieve user data.
35 | */
36 | Observable userEntityDetails(final int userId);
37 | }
38 |
--------------------------------------------------------------------------------
/data/src/main/java/com/fernandocejas/android10/sample/data/repository/datasource/UserDataStoreFactory.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (C) 2015 Fernando Cejas Open Source Project
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.fernandocejas.android10.sample.data.repository.datasource;
17 |
18 | import android.content.Context;
19 | import android.support.annotation.NonNull;
20 | import com.fernandocejas.android10.sample.data.cache.UserCache;
21 | import com.fernandocejas.android10.sample.data.entity.mapper.UserEntityJsonMapper;
22 | import com.fernandocejas.android10.sample.data.net.RestApi;
23 | import com.fernandocejas.android10.sample.data.net.RestApiImpl;
24 | import javax.inject.Inject;
25 | import javax.inject.Singleton;
26 |
27 | /**
28 | * Factory that creates different implementations of {@link UserDataStore}.
29 | */
30 | @Singleton
31 | public class UserDataStoreFactory {
32 |
33 | private final Context context;
34 | private final UserCache userCache;
35 |
36 | @Inject
37 | UserDataStoreFactory(@NonNull Context context, @NonNull UserCache userCache) {
38 | this.context = context.getApplicationContext();
39 | this.userCache = userCache;
40 | }
41 |
42 | /**
43 | * Create {@link UserDataStore} from a user id.
44 | */
45 | public UserDataStore create(int userId) {
46 | UserDataStore userDataStore;
47 |
48 | if (!this.userCache.isExpired() && this.userCache.isCached(userId)) {
49 | userDataStore = new DiskUserDataStore(this.userCache);
50 | } else {
51 | userDataStore = createCloudDataStore();
52 | }
53 |
54 | return userDataStore;
55 | }
56 |
57 | /**
58 | * Create {@link UserDataStore} to retrieve data from the Cloud.
59 | */
60 | public UserDataStore createCloudDataStore() {
61 | final UserEntityJsonMapper userEntityJsonMapper = new UserEntityJsonMapper();
62 | final RestApi restApi = new RestApiImpl(this.context, userEntityJsonMapper);
63 |
64 | return new CloudUserDataStore(restApi, this.userCache);
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/data/src/test/java/com/fernandocejas/android10/sample/data/ApplicationStub.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (C) 2015 android10.org Open Source Project
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.fernandocejas.android10.sample.data;
17 |
18 | import android.app.Application;
19 |
20 | public class ApplicationStub extends Application {}
21 |
--------------------------------------------------------------------------------
/data/src/test/java/com/fernandocejas/android10/sample/data/ApplicationTestCase.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (C) 2015 Fernando Cejas Open Source Project
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.fernandocejas.android10.sample.data;
17 |
18 | import android.content.Context;
19 | import java.io.File;
20 | import org.junit.Rule;
21 | import org.junit.rules.TestRule;
22 | import org.junit.runner.RunWith;
23 | import org.mockito.MockitoAnnotations;
24 | import org.robolectric.RobolectricTestRunner;
25 | import org.robolectric.RuntimeEnvironment;
26 | import org.robolectric.annotation.Config;
27 |
28 | /**
29 | * Base class for Robolectric data layer tests.
30 | * Inherit from this class to create a test.
31 | */
32 | @RunWith(RobolectricTestRunner.class)
33 | @Config(constants = BuildConfig.class, application = ApplicationStub.class, sdk = 21)
34 | public abstract class ApplicationTestCase {
35 |
36 | @Rule public TestRule injectMocksRule = (base, description) -> {
37 | MockitoAnnotations.initMocks(ApplicationTestCase.this);
38 | return base;
39 | };
40 |
41 | public static Context context() {
42 | return RuntimeEnvironment.application;
43 | }
44 |
45 | public static File cacheDir() {
46 | return RuntimeEnvironment.application.getCacheDir();
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/data/src/test/java/com/fernandocejas/android10/sample/data/cache/FileManagerTest.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (C) 2015 Fernando Cejas Open Source Project
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.fernandocejas.android10.sample.data.cache;
17 |
18 | import com.fernandocejas.android10.sample.data.ApplicationTestCase;
19 | import java.io.File;
20 | import org.junit.After;
21 | import org.junit.Before;
22 | import org.junit.Test;
23 |
24 | import static org.hamcrest.CoreMatchers.equalTo;
25 | import static org.hamcrest.CoreMatchers.is;
26 | import static org.hamcrest.MatcherAssert.assertThat;
27 |
28 | public class FileManagerTest extends ApplicationTestCase {
29 |
30 | private FileManager fileManager;
31 |
32 | @Before
33 | public void setUp() {
34 | fileManager = new FileManager();
35 | }
36 |
37 | @After
38 | public void tearDown() {
39 | if (cacheDir() != null) {
40 | fileManager.clearDirectory(cacheDir());
41 | }
42 | }
43 |
44 | @Test
45 | public void testWriteToFile() {
46 | File fileToWrite = createDummyFile();
47 | String fileContent = "content";
48 |
49 | fileManager.writeToFile(fileToWrite, fileContent);
50 |
51 | assertThat(fileToWrite.exists(), is(true));
52 | }
53 |
54 | @Test
55 | public void testFileContent() {
56 | File fileToWrite = createDummyFile();
57 | String fileContent = "content\n";
58 |
59 | fileManager.writeToFile(fileToWrite, fileContent);
60 | String expectedContent = fileManager.readFileContent(fileToWrite);
61 |
62 | assertThat(expectedContent, is(equalTo(fileContent)));
63 | }
64 |
65 | private File createDummyFile() {
66 | String dummyFilePath = cacheDir().getPath() + File.separator + "dummyFile";
67 | return new File(dummyFilePath);
68 | }
69 | }
70 |
--------------------------------------------------------------------------------
/data/src/test/java/com/fernandocejas/android10/sample/data/cache/serializer/SerializerTest.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (C) 2015 Fernando Cejas Open Source Project
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.fernandocejas.android10.sample.data.cache.serializer;
17 |
18 | import com.fernandocejas.android10.sample.data.entity.UserEntity;
19 | import org.junit.Before;
20 | import org.junit.Test;
21 | import org.junit.runner.RunWith;
22 | import org.mockito.runners.MockitoJUnitRunner;
23 |
24 | import static org.hamcrest.CoreMatchers.equalTo;
25 | import static org.hamcrest.CoreMatchers.is;
26 | import static org.junit.Assert.assertThat;
27 |
28 | @RunWith(MockitoJUnitRunner.class)
29 | public class SerializerTest {
30 |
31 | private static final String JSON_RESPONSE = "{\n"
32 | + " \"id\": 1,\n"
33 | + " \"cover_url\": \"http://www.android10.org/myapi/cover_1.jpg\",\n"
34 | + " \"full_name\": \"Simon Hill\",\n"
35 | + " \"description\": \"Curabitur gravida nisi at nibh. In hac habitasse platea dictumst. Aliquam augue quam, sollicitudin vitae, consectetuer eget, rutrum at, lorem.\\n\\nInteger tincidunt ante vel ipsum. Praesent blandit lacinia erat. Vestibulum sed magna at nunc commodo placerat.\\n\\nPraesent blandit. Nam nulla. Integer pede justo, lacinia eget, tincidunt eget, tempus vel, pede.\",\n"
36 | + " \"followers\": 7484,\n"
37 | + " \"email\": \"jcooper@babbleset.edu\"\n"
38 | + "}";
39 |
40 | private Serializer serializer;
41 |
42 | @Before
43 | public void setUp() {
44 | serializer = new Serializer();
45 | }
46 |
47 | @Test
48 | public void testSerializeHappyCase() {
49 | final UserEntity userEntityOne = serializer.deserialize(JSON_RESPONSE, UserEntity.class);
50 | final String jsonString = serializer.serialize(userEntityOne, UserEntity.class);
51 | final UserEntity userEntityTwo = serializer.deserialize(jsonString, UserEntity.class);
52 |
53 | assertThat(userEntityOne.getUserId(), is(userEntityTwo.getUserId()));
54 | assertThat(userEntityOne.getFullname(), is(equalTo(userEntityTwo.getFullname())));
55 | assertThat(userEntityOne.getFollowers(), is(userEntityTwo.getFollowers()));
56 | }
57 |
58 | @Test
59 | public void testDesearializeHappyCase() {
60 | final UserEntity userEntity = serializer.deserialize(JSON_RESPONSE, UserEntity.class);
61 |
62 | assertThat(userEntity.getUserId(), is(1));
63 | assertThat(userEntity.getFullname(), is("Simon Hill"));
64 | assertThat(userEntity.getFollowers(), is(7484));
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/data/src/test/java/com/fernandocejas/android10/sample/data/entity/mapper/UserEntityDataMapperTest.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (C) 2015 Fernando Cejas Open Source Project
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.fernandocejas.android10.sample.data.entity.mapper;
17 |
18 | import com.fernandocejas.android10.sample.data.entity.UserEntity;
19 | import com.fernandocejas.android10.sample.domain.User;
20 | import java.util.ArrayList;
21 | import java.util.Collection;
22 | import java.util.List;
23 | import org.junit.Before;
24 | import org.junit.Test;
25 | import org.junit.runner.RunWith;
26 | import org.mockito.runners.MockitoJUnitRunner;
27 |
28 | import static org.hamcrest.CoreMatchers.instanceOf;
29 | import static org.hamcrest.CoreMatchers.is;
30 | import static org.hamcrest.MatcherAssert.assertThat;
31 | import static org.mockito.Mockito.mock;
32 |
33 | @RunWith(MockitoJUnitRunner.class)
34 | public class UserEntityDataMapperTest {
35 |
36 | private static final int FAKE_USER_ID = 123;
37 | private static final String FAKE_FULLNAME = "Tony Stark";
38 |
39 | private UserEntityDataMapper userEntityDataMapper;
40 |
41 | @Before
42 | public void setUp() throws Exception {
43 | userEntityDataMapper = new UserEntityDataMapper();
44 | }
45 |
46 | @Test
47 | public void testTransformUserEntity() {
48 | UserEntity userEntity = createFakeUserEntity();
49 | User user = userEntityDataMapper.transform(userEntity);
50 |
51 | assertThat(user, is(instanceOf(User.class)));
52 | assertThat(user.getUserId(), is(FAKE_USER_ID));
53 | assertThat(user.getFullName(), is(FAKE_FULLNAME));
54 | }
55 |
56 | @Test
57 | public void testTransformUserEntityCollection() {
58 | UserEntity mockUserEntityOne = mock(UserEntity.class);
59 | UserEntity mockUserEntityTwo = mock(UserEntity.class);
60 |
61 | List userEntityList = new ArrayList(5);
62 | userEntityList.add(mockUserEntityOne);
63 | userEntityList.add(mockUserEntityTwo);
64 |
65 | Collection userCollection = userEntityDataMapper.transform(userEntityList);
66 |
67 | assertThat(userCollection.toArray()[0], is(instanceOf(User.class)));
68 | assertThat(userCollection.toArray()[1], is(instanceOf(User.class)));
69 | assertThat(userCollection.size(), is(2));
70 | }
71 |
72 | private UserEntity createFakeUserEntity() {
73 | UserEntity userEntity = new UserEntity();
74 | userEntity.setUserId(FAKE_USER_ID);
75 | userEntity.setFullname(FAKE_FULLNAME);
76 |
77 | return userEntity;
78 | }
79 | }
80 |
--------------------------------------------------------------------------------
/data/src/test/java/com/fernandocejas/android10/sample/data/entity/mapper/UserEntityJsonMapperTest.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (C) 2015 Fernando Cejas Open Source Project
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.fernandocejas.android10.sample.data.entity.mapper;
17 |
18 | import com.fernandocejas.android10.sample.data.entity.UserEntity;
19 | import com.google.gson.JsonSyntaxException;
20 | import java.util.Collection;
21 | import org.junit.Before;
22 | import org.junit.Rule;
23 | import org.junit.Test;
24 | import org.junit.rules.ExpectedException;
25 | import org.junit.runner.RunWith;
26 | import org.mockito.runners.MockitoJUnitRunner;
27 |
28 | import static org.hamcrest.CoreMatchers.equalTo;
29 | import static org.hamcrest.CoreMatchers.is;
30 | import static org.hamcrest.MatcherAssert.assertThat;
31 |
32 | @RunWith(MockitoJUnitRunner.class)
33 | public class UserEntityJsonMapperTest {
34 |
35 | private static final String JSON_RESPONSE_USER_DETAILS = "{\n"
36 | + " \"id\": 1,\n"
37 | + " \"cover_url\": \"http://www.android10.org/myapi/cover_1.jpg\",\n"
38 | + " \"full_name\": \"Simon Hill\",\n"
39 | + " \"description\": \"Curabitur gravida nisi at nibh. In hac habitasse platea dictumst. Aliquam augue quam, sollicitudin vitae, consectetuer eget, rutrum at, lorem.\\n\\nInteger tincidunt ante vel ipsum. Praesent blandit lacinia erat. Vestibulum sed magna at nunc commodo placerat.\\n\\nPraesent blandit. Nam nulla. Integer pede justo, lacinia eget, tincidunt eget, tempus vel, pede.\",\n"
40 | + " \"followers\": 7484,\n"
41 | + " \"email\": \"jcooper@babbleset.edu\"\n"
42 | + "}";
43 |
44 | private static final String JSON_RESPONSE_USER_COLLECTION = "[{\n"
45 | + " \"id\": 1,\n"
46 | + " \"full_name\": \"Simon Hill\",\n"
47 | + " \"followers\": 7484\n"
48 | + "}, {\n"
49 | + " \"id\": 12,\n"
50 | + " \"full_name\": \"Pedro Garcia\",\n"
51 | + " \"followers\": 1381\n"
52 | + "}]";
53 |
54 | private UserEntityJsonMapper userEntityJsonMapper;
55 |
56 | @Rule
57 | public ExpectedException expectedException = ExpectedException.none();
58 |
59 | @Before
60 | public void setUp() {
61 | userEntityJsonMapper = new UserEntityJsonMapper();
62 | }
63 |
64 | @Test
65 | public void testTransformUserEntityHappyCase() {
66 | UserEntity userEntity = userEntityJsonMapper.transformUserEntity(JSON_RESPONSE_USER_DETAILS);
67 |
68 | assertThat(userEntity.getUserId(), is(1));
69 | assertThat(userEntity.getFullname(), is(equalTo("Simon Hill")));
70 | assertThat(userEntity.getEmail(), is(equalTo("jcooper@babbleset.edu")));
71 | }
72 |
73 | @Test
74 | public void testTransformUserEntityCollectionHappyCase() {
75 | Collection userEntityCollection =
76 | userEntityJsonMapper.transformUserEntityCollection(
77 | JSON_RESPONSE_USER_COLLECTION);
78 |
79 | assertThat(((UserEntity) userEntityCollection.toArray()[0]).getUserId(), is(1));
80 | assertThat(((UserEntity) userEntityCollection.toArray()[1]).getUserId(), is(12));
81 | assertThat(userEntityCollection.size(), is(2));
82 | }
83 |
84 | @Test
85 | public void testTransformUserEntityNotValidResponse() {
86 | expectedException.expect(JsonSyntaxException.class);
87 | userEntityJsonMapper.transformUserEntity("ironman");
88 | }
89 |
90 | @Test
91 | public void testTransformUserEntityCollectionNotValidResponse() {
92 | expectedException.expect(JsonSyntaxException.class);
93 | userEntityJsonMapper.transformUserEntityCollection("Tony Stark");
94 | }
95 | }
96 |
--------------------------------------------------------------------------------
/data/src/test/java/com/fernandocejas/android10/sample/data/exception/RepositoryErrorBundleTest.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (C) 2015 Fernando Cejas Open Source Project
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.fernandocejas.android10.sample.data.exception;
17 |
18 | import org.junit.Before;
19 | import org.junit.Test;
20 | import org.junit.runner.RunWith;
21 | import org.mockito.Mock;
22 | import org.mockito.runners.MockitoJUnitRunner;
23 |
24 | import static org.mockito.Mockito.verify;
25 |
26 | @RunWith(MockitoJUnitRunner.class)
27 | public class RepositoryErrorBundleTest {
28 |
29 | private RepositoryErrorBundle repositoryErrorBundle;
30 |
31 | @Mock private Exception mockException;
32 |
33 | @Before
34 | public void setUp() {
35 | repositoryErrorBundle = new RepositoryErrorBundle(mockException);
36 | }
37 |
38 | @Test
39 | @SuppressWarnings("ThrowableResultOfMethodCallIgnored")
40 | public void testGetErrorMessageInteraction() {
41 | repositoryErrorBundle.getErrorMessage();
42 |
43 | verify(mockException).getMessage();
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/data/src/test/java/com/fernandocejas/android10/sample/data/repository/UserDataRepositoryTest.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (C) 2015 Fernando Cejas Open Source Project
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.fernandocejas.android10.sample.data.repository;
17 |
18 | import com.fernandocejas.android10.sample.data.entity.UserEntity;
19 | import com.fernandocejas.android10.sample.data.entity.mapper.UserEntityDataMapper;
20 | import com.fernandocejas.android10.sample.data.repository.datasource.UserDataStore;
21 | import com.fernandocejas.android10.sample.data.repository.datasource.UserDataStoreFactory;
22 | import com.fernandocejas.android10.sample.domain.User;
23 | import io.reactivex.Observable;
24 | import java.util.ArrayList;
25 | import java.util.List;
26 | import org.junit.Before;
27 | import org.junit.Test;
28 | import org.junit.runner.RunWith;
29 | import org.mockito.Mock;
30 | import org.mockito.runners.MockitoJUnitRunner;
31 |
32 | import static org.mockito.BDDMockito.given;
33 | import static org.mockito.Matchers.anyInt;
34 | import static org.mockito.Mockito.verify;
35 |
36 | @RunWith(MockitoJUnitRunner.class)
37 | public class UserDataRepositoryTest {
38 |
39 | private static final int FAKE_USER_ID = 123;
40 |
41 | private UserDataRepository userDataRepository;
42 |
43 | @Mock private UserDataStoreFactory mockUserDataStoreFactory;
44 | @Mock private UserEntityDataMapper mockUserEntityDataMapper;
45 | @Mock private UserDataStore mockUserDataStore;
46 | @Mock private UserEntity mockUserEntity;
47 | @Mock private User mockUser;
48 |
49 | @Before
50 | public void setUp() {
51 | userDataRepository = new UserDataRepository(mockUserDataStoreFactory, mockUserEntityDataMapper);
52 | given(mockUserDataStoreFactory.create(anyInt())).willReturn(mockUserDataStore);
53 | given(mockUserDataStoreFactory.createCloudDataStore()).willReturn(mockUserDataStore);
54 | }
55 |
56 | @Test
57 | public void testGetUsersHappyCase() {
58 | List usersList = new ArrayList<>();
59 | usersList.add(new UserEntity());
60 | given(mockUserDataStore.userEntityList()).willReturn(Observable.just(usersList));
61 |
62 | userDataRepository.users();
63 |
64 | verify(mockUserDataStoreFactory).createCloudDataStore();
65 | verify(mockUserDataStore).userEntityList();
66 | }
67 |
68 | @Test
69 | public void testGetUserHappyCase() {
70 | UserEntity userEntity = new UserEntity();
71 | given(mockUserDataStore.userEntityDetails(FAKE_USER_ID)).willReturn(Observable.just(userEntity));
72 | userDataRepository.user(FAKE_USER_ID);
73 |
74 | verify(mockUserDataStoreFactory).create(FAKE_USER_ID);
75 | verify(mockUserDataStore).userEntityDetails(FAKE_USER_ID);
76 | }
77 | }
78 |
--------------------------------------------------------------------------------
/data/src/test/java/com/fernandocejas/android10/sample/data/repository/datasource/CloudUserDataStoreTest.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (C) 2015 Fernando Cejas Open Source Project
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.fernandocejas.android10.sample.data.repository.datasource;
17 |
18 | import com.fernandocejas.android10.sample.data.cache.UserCache;
19 | import com.fernandocejas.android10.sample.data.entity.UserEntity;
20 | import com.fernandocejas.android10.sample.data.net.RestApi;
21 | import io.reactivex.Observable;
22 | import org.junit.Before;
23 | import org.junit.Test;
24 | import org.junit.runner.RunWith;
25 | import org.mockito.Mock;
26 | import org.mockito.runners.MockitoJUnitRunner;
27 |
28 | import static org.mockito.BDDMockito.given;
29 | import static org.mockito.Mockito.verify;
30 |
31 | @RunWith(MockitoJUnitRunner.class)
32 | public class CloudUserDataStoreTest {
33 |
34 | private static final int FAKE_USER_ID = 765;
35 |
36 | private CloudUserDataStore cloudUserDataStore;
37 |
38 | @Mock private RestApi mockRestApi;
39 | @Mock private UserCache mockUserCache;
40 |
41 | @Before
42 | public void setUp() {
43 | cloudUserDataStore = new CloudUserDataStore(mockRestApi, mockUserCache);
44 | }
45 |
46 | @Test
47 | public void testGetUserEntityListFromApi() {
48 | cloudUserDataStore.userEntityList();
49 | verify(mockRestApi).userEntityList();
50 | }
51 |
52 | @Test
53 | public void testGetUserEntityDetailsFromApi() {
54 | UserEntity fakeUserEntity = new UserEntity();
55 | Observable fakeObservable = Observable.just(fakeUserEntity);
56 | given(mockRestApi.userEntityById(FAKE_USER_ID)).willReturn(fakeObservable);
57 |
58 | cloudUserDataStore.userEntityDetails(FAKE_USER_ID);
59 |
60 | verify(mockRestApi).userEntityById(FAKE_USER_ID);
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/data/src/test/java/com/fernandocejas/android10/sample/data/repository/datasource/DiskUserDataStoreTest.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (C) 2015 Fernando Cejas Open Source Project
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.fernandocejas.android10.sample.data.repository.datasource;
17 |
18 | import com.fernandocejas.android10.sample.data.cache.UserCache;
19 | import org.junit.Before;
20 | import org.junit.Rule;
21 | import org.junit.Test;
22 | import org.junit.rules.ExpectedException;
23 | import org.junit.runner.RunWith;
24 | import org.mockito.Mock;
25 | import org.mockito.runners.MockitoJUnitRunner;
26 |
27 | import static org.mockito.Mockito.verify;
28 |
29 | @RunWith(MockitoJUnitRunner.class)
30 | public class DiskUserDataStoreTest {
31 |
32 | private static final int FAKE_USER_ID = 11;
33 |
34 | private DiskUserDataStore diskUserDataStore;
35 |
36 | @Mock private UserCache mockUserCache;
37 |
38 | @Rule public ExpectedException expectedException = ExpectedException.none();
39 |
40 | @Before
41 | public void setUp() {
42 | diskUserDataStore = new DiskUserDataStore(mockUserCache);
43 | }
44 |
45 | @Test
46 | public void testGetUserEntityListUnsupported() {
47 | expectedException.expect(UnsupportedOperationException.class);
48 | diskUserDataStore.userEntityList();
49 | }
50 |
51 | @Test
52 | public void testGetUserEntityDetailesFromCache() {
53 | diskUserDataStore.userEntityDetails(FAKE_USER_ID);
54 | verify(mockUserCache).get(FAKE_USER_ID);
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/data/src/test/java/com/fernandocejas/android10/sample/data/repository/datasource/UserDataStoreFactoryTest.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (C) 2015 Fernando Cejas Open Source Project
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.fernandocejas.android10.sample.data.repository.datasource;
17 |
18 | import com.fernandocejas.android10.sample.data.ApplicationTestCase;
19 | import com.fernandocejas.android10.sample.data.cache.UserCache;
20 | import org.junit.Before;
21 | import org.junit.Test;
22 | import org.mockito.Mock;
23 | import org.robolectric.RuntimeEnvironment;
24 |
25 | import static org.hamcrest.CoreMatchers.instanceOf;
26 | import static org.hamcrest.CoreMatchers.is;
27 | import static org.hamcrest.CoreMatchers.notNullValue;
28 | import static org.hamcrest.MatcherAssert.assertThat;
29 | import static org.mockito.BDDMockito.given;
30 | import static org.mockito.Mockito.verify;
31 |
32 | public class UserDataStoreFactoryTest extends ApplicationTestCase {
33 |
34 | private static final int FAKE_USER_ID = 11;
35 |
36 | private UserDataStoreFactory userDataStoreFactory;
37 |
38 | @Mock private UserCache mockUserCache;
39 |
40 | @Before
41 | public void setUp() {
42 | userDataStoreFactory = new UserDataStoreFactory(RuntimeEnvironment.application, mockUserCache);
43 | }
44 |
45 | @Test
46 | public void testCreateDiskDataStore() {
47 | given(mockUserCache.isCached(FAKE_USER_ID)).willReturn(true);
48 | given(mockUserCache.isExpired()).willReturn(false);
49 |
50 | UserDataStore userDataStore = userDataStoreFactory.create(FAKE_USER_ID);
51 |
52 | assertThat(userDataStore, is(notNullValue()));
53 | assertThat(userDataStore, is(instanceOf(DiskUserDataStore.class)));
54 |
55 | verify(mockUserCache).isCached(FAKE_USER_ID);
56 | verify(mockUserCache).isExpired();
57 | }
58 |
59 | @Test
60 | public void testCreateCloudDataStore() {
61 | given(mockUserCache.isExpired()).willReturn(true);
62 | given(mockUserCache.isCached(FAKE_USER_ID)).willReturn(false);
63 |
64 | UserDataStore userDataStore = userDataStoreFactory.create(FAKE_USER_ID);
65 |
66 | assertThat(userDataStore, is(notNullValue()));
67 | assertThat(userDataStore, is(instanceOf(CloudUserDataStore.class)));
68 |
69 | verify(mockUserCache).isExpired();
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/domain/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'java'
2 |
3 | //noinspection GroovyUnusedAssignment
4 | sourceCompatibility = 1.7
5 | //noinspection GroovyUnusedAssignment
6 | targetCompatibility = 1.7
7 |
8 | configurations {
9 | provided
10 | }
11 |
12 | sourceSets {
13 | main {
14 | compileClasspath += configurations.provided
15 | }
16 | }
17 |
18 | dependencies {
19 | def domainDependencies = rootProject.ext.domainDependencies
20 | def domainTestDependencies = rootProject.ext.domainTestDependencies
21 |
22 | compileOnly domainDependencies.javaxAnnotation
23 |
24 | implementation domainDependencies.javaxInject
25 | implementation domainDependencies.rxJava
26 | compile domainDependencies.arrow
27 |
28 | testImplementation domainTestDependencies.junit
29 | testImplementation domainTestDependencies.mockito
30 | testImplementation domainTestDependencies.assertj
31 | }
32 |
--------------------------------------------------------------------------------
/domain/src/main/java/com/fernandocejas/android10/sample/domain/User.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (C) 2015 Fernando Cejas Open Source Project
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.fernandocejas.android10.sample.domain;
17 |
18 | /**
19 | * Class that represents a User in the domain layer.
20 | */
21 | public class User {
22 |
23 | private final int userId;
24 |
25 | public User(int userId) {
26 | this.userId = userId;
27 | }
28 |
29 | private String coverUrl;
30 | private String fullName;
31 | private String email;
32 | private String description;
33 | private int followers;
34 |
35 | public int getUserId() {
36 | return userId;
37 | }
38 |
39 | public String getCoverUrl() {
40 | return coverUrl;
41 | }
42 |
43 | public void setCoverUrl(String coverUrl) {
44 | this.coverUrl = coverUrl;
45 | }
46 |
47 | public String getFullName() {
48 | return fullName;
49 | }
50 |
51 | public void setFullName(String fullName) {
52 | this.fullName = fullName;
53 | }
54 |
55 | public String getEmail() {
56 | return email;
57 | }
58 |
59 | public void setEmail(String email) {
60 | this.email = email;
61 | }
62 |
63 | public String getDescription() {
64 | return description;
65 | }
66 |
67 | public void setDescription(String description) {
68 | this.description = description;
69 | }
70 |
71 | public int getFollowers() {
72 | return followers;
73 | }
74 |
75 | public void setFollowers(int followers) {
76 | this.followers = followers;
77 | }
78 | }
79 |
--------------------------------------------------------------------------------
/domain/src/main/java/com/fernandocejas/android10/sample/domain/exception/DefaultErrorBundle.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (C) 2015 Fernando Cejas Open Source Project
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.fernandocejas.android10.sample.domain.exception;
17 |
18 | /**
19 | * Wrapper around Exceptions used to manage default errors.
20 | */
21 | public class DefaultErrorBundle implements ErrorBundle {
22 |
23 | private static final String DEFAULT_ERROR_MSG = "Unknown error";
24 |
25 | private final Exception exception;
26 |
27 | public DefaultErrorBundle(Exception exception) {
28 | this.exception = exception;
29 | }
30 |
31 | @Override
32 | public Exception getException() {
33 | return exception;
34 | }
35 |
36 | @Override
37 | public String getErrorMessage() {
38 | return (exception != null) ? this.exception.getMessage() : DEFAULT_ERROR_MSG;
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/domain/src/main/java/com/fernandocejas/android10/sample/domain/exception/ErrorBundle.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (C) 2015 Fernando Cejas Open Source Project
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.fernandocejas.android10.sample.domain.exception;
17 |
18 | /**
19 | * Interface to represent a wrapper around an {@link java.lang.Exception} to manage errors.
20 | */
21 | public interface ErrorBundle {
22 | Exception getException();
23 |
24 | String getErrorMessage();
25 | }
26 |
--------------------------------------------------------------------------------
/domain/src/main/java/com/fernandocejas/android10/sample/domain/executor/PostExecutionThread.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (C) 2015 Fernando Cejas Open Source Project
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.fernandocejas.android10.sample.domain.executor;
17 |
18 | import io.reactivex.Scheduler;
19 |
20 | /**
21 | * Thread abstraction created to change the execution context from any thread to any other thread.
22 | * Useful to encapsulate a UI Thread for example, since some job will be done in background, an
23 | * implementation of this interface will change context and update the UI.
24 | */
25 | public interface PostExecutionThread {
26 | Scheduler getScheduler();
27 | }
28 |
--------------------------------------------------------------------------------
/domain/src/main/java/com/fernandocejas/android10/sample/domain/executor/ThreadExecutor.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (C) 2015 Fernando Cejas Open Source Project
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.fernandocejas.android10.sample.domain.executor;
17 |
18 | import java.util.concurrent.Executor;
19 |
20 | /**
21 | * Executor implementation can be based on different frameworks or techniques of asynchronous
22 | * execution, but every implementation will execute the
23 | * {@link com.fernandocejas.android10.sample.domain.interactor.UseCase} out of the UI thread.
24 | */
25 | public interface ThreadExecutor extends Executor {}
26 |
--------------------------------------------------------------------------------
/domain/src/main/java/com/fernandocejas/android10/sample/domain/interactor/DefaultObserver.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (C) 2015 Fernando Cejas Open Source Project
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.fernandocejas.android10.sample.domain.interactor;
17 |
18 | import io.reactivex.observers.DisposableObserver;
19 |
20 | /**
21 | * Default {@link DisposableObserver} base class to be used whenever you want default error handling.
22 | */
23 | public class DefaultObserver extends DisposableObserver {
24 | @Override public void onNext(T t) {
25 | // no-op by default.
26 | }
27 |
28 | @Override public void onComplete() {
29 | // no-op by default.
30 | }
31 |
32 | @Override public void onError(Throwable exception) {
33 | // no-op by default.
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/domain/src/main/java/com/fernandocejas/android10/sample/domain/interactor/GetUserDetails.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (C) 2015 Fernando Cejas Open Source Project
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.fernandocejas.android10.sample.domain.interactor;
17 |
18 | import com.fernandocejas.android10.sample.domain.User;
19 | import com.fernandocejas.android10.sample.domain.executor.PostExecutionThread;
20 | import com.fernandocejas.android10.sample.domain.executor.ThreadExecutor;
21 | import com.fernandocejas.android10.sample.domain.repository.UserRepository;
22 | import com.fernandocejas.arrow.checks.Preconditions;
23 | import io.reactivex.Observable;
24 | import javax.inject.Inject;
25 |
26 | /**
27 | * This class is an implementation of {@link UseCase} that represents a use case for
28 | * retrieving data related to an specific {@link User}.
29 | */
30 | public class GetUserDetails extends UseCase {
31 |
32 | private final UserRepository userRepository;
33 |
34 | @Inject
35 | GetUserDetails(UserRepository userRepository, ThreadExecutor threadExecutor,
36 | PostExecutionThread postExecutionThread) {
37 | super(threadExecutor, postExecutionThread);
38 | this.userRepository = userRepository;
39 | }
40 |
41 | @Override Observable buildUseCaseObservable(Params params) {
42 | Preconditions.checkNotNull(params);
43 | return this.userRepository.user(params.userId);
44 | }
45 |
46 | public static final class Params {
47 |
48 | private final int userId;
49 |
50 | private Params(int userId) {
51 | this.userId = userId;
52 | }
53 |
54 | public static Params forUser(int userId) {
55 | return new Params(userId);
56 | }
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/domain/src/main/java/com/fernandocejas/android10/sample/domain/interactor/GetUserList.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (C) 2015 Fernando Cejas Open Source Project
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.fernandocejas.android10.sample.domain.interactor;
17 |
18 | import com.fernandocejas.android10.sample.domain.User;
19 | import com.fernandocejas.android10.sample.domain.executor.PostExecutionThread;
20 | import com.fernandocejas.android10.sample.domain.executor.ThreadExecutor;
21 | import com.fernandocejas.android10.sample.domain.repository.UserRepository;
22 | import io.reactivex.Observable;
23 | import java.util.List;
24 | import javax.inject.Inject;
25 |
26 | /**
27 | * This class is an implementation of {@link UseCase} that represents a use case for
28 | * retrieving a collection of all {@link User}.
29 | */
30 | public class GetUserList extends UseCase, Void> {
31 |
32 | private final UserRepository userRepository;
33 |
34 | @Inject
35 | GetUserList(UserRepository userRepository, ThreadExecutor threadExecutor,
36 | PostExecutionThread postExecutionThread) {
37 | super(threadExecutor, postExecutionThread);
38 | this.userRepository = userRepository;
39 | }
40 |
41 | @Override Observable> buildUseCaseObservable(Void unused) {
42 | return this.userRepository.users();
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/domain/src/main/java/com/fernandocejas/android10/sample/domain/interactor/UseCase.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (C) 2015 Fernando Cejas Open Source Project
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.fernandocejas.android10.sample.domain.interactor;
17 |
18 | import com.fernandocejas.android10.sample.domain.executor.PostExecutionThread;
19 | import com.fernandocejas.android10.sample.domain.executor.ThreadExecutor;
20 | import com.fernandocejas.arrow.checks.Preconditions;
21 | import io.reactivex.Observable;
22 | import io.reactivex.disposables.CompositeDisposable;
23 | import io.reactivex.disposables.Disposable;
24 | import io.reactivex.observers.DisposableObserver;
25 | import io.reactivex.schedulers.Schedulers;
26 |
27 | /**
28 | * Abstract class for a Use Case (Interactor in terms of Clean Architecture).
29 | * This interface represents a execution unit for different use cases (this means any use case
30 | * in the application should implement this contract).
31 | *
32 | * By convention each UseCase implementation will return the result using a {@link DisposableObserver}
33 | * that will execute its job in a background thread and will post the result in the UI thread.
34 | */
35 | public abstract class UseCase {
36 |
37 | private final ThreadExecutor threadExecutor;
38 | private final PostExecutionThread postExecutionThread;
39 | private final CompositeDisposable disposables;
40 |
41 | UseCase(ThreadExecutor threadExecutor, PostExecutionThread postExecutionThread) {
42 | this.threadExecutor = threadExecutor;
43 | this.postExecutionThread = postExecutionThread;
44 | this.disposables = new CompositeDisposable();
45 | }
46 |
47 | /**
48 | * Builds an {@link Observable} which will be used when executing the current {@link UseCase}.
49 | */
50 | abstract Observable buildUseCaseObservable(Params params);
51 |
52 | /**
53 | * Executes the current use case.
54 | *
55 | * @param observer {@link DisposableObserver} which will be listening to the observable build
56 | * by {@link #buildUseCaseObservable(Params)} ()} method.
57 | * @param params Parameters (Optional) used to build/execute this use case.
58 | */
59 | public void execute(DisposableObserver observer, Params params) {
60 | Preconditions.checkNotNull(observer);
61 | final Observable observable = this.buildUseCaseObservable(params)
62 | .subscribeOn(Schedulers.from(threadExecutor))
63 | .observeOn(postExecutionThread.getScheduler());
64 | addDisposable(observable.subscribeWith(observer));
65 | }
66 |
67 | /**
68 | * Dispose from current {@link CompositeDisposable}.
69 | */
70 | public void dispose() {
71 | if (!disposables.isDisposed()) {
72 | disposables.dispose();
73 | }
74 | }
75 |
76 | /**
77 | * Dispose from current {@link CompositeDisposable}.
78 | */
79 | private void addDisposable(Disposable disposable) {
80 | Preconditions.checkNotNull(disposable);
81 | Preconditions.checkNotNull(disposables);
82 | disposables.add(disposable);
83 | }
84 | }
85 |
--------------------------------------------------------------------------------
/domain/src/main/java/com/fernandocejas/android10/sample/domain/repository/UserRepository.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (C) 2015 Fernando Cejas Open Source Project
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.fernandocejas.android10.sample.domain.repository;
17 |
18 | import com.fernandocejas.android10.sample.domain.User;
19 | import io.reactivex.Observable;
20 | import java.util.List;
21 |
22 | /**
23 | * Interface that represents a Repository for getting {@link User} related data.
24 | */
25 | public interface UserRepository {
26 | /**
27 | * Get an {@link Observable} which will emit a List of {@link User}.
28 | */
29 | Observable> users();
30 |
31 | /**
32 | * Get an {@link Observable} which will emit a {@link User}.
33 | *
34 | * @param userId The user id used to retrieve user data.
35 | */
36 | Observable user(final int userId);
37 | }
38 |
--------------------------------------------------------------------------------
/domain/src/test/java/com/fernandocejas/android10/sample/domain/UserTest.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (C) 2015 Fernando Cejas Open Source Project
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.fernandocejas.android10.sample.domain;
17 |
18 | import org.junit.Before;
19 | import org.junit.Test;
20 |
21 | import static org.assertj.core.api.Assertions.assertThat;
22 |
23 | public class UserTest {
24 |
25 | private static final int FAKE_USER_ID = 8;
26 |
27 | private User user;
28 |
29 | @Before
30 | public void setUp() {
31 | user = new User(FAKE_USER_ID);
32 | }
33 |
34 | @Test
35 | public void testUserConstructorHappyCase() {
36 | final int userId = user.getUserId();
37 |
38 | assertThat(userId).isEqualTo(FAKE_USER_ID);
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/domain/src/test/java/com/fernandocejas/android10/sample/domain/exception/DefaultErrorBundleTest.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (C) 2015 Fernando Cejas Open Source Project
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.fernandocejas.android10.sample.domain.exception;
17 |
18 | import org.junit.Before;
19 | import org.junit.Test;
20 | import org.junit.runner.RunWith;
21 | import org.mockito.Mock;
22 | import org.mockito.runners.MockitoJUnitRunner;
23 |
24 | import static org.mockito.Mockito.verify;
25 |
26 | @RunWith(MockitoJUnitRunner.class)
27 | public class DefaultErrorBundleTest {
28 | private DefaultErrorBundle defaultErrorBundle;
29 |
30 | @Mock private Exception mockException;
31 |
32 | @Before
33 | public void setUp() {
34 | defaultErrorBundle = new DefaultErrorBundle(mockException);
35 | }
36 |
37 | @Test
38 | public void testGetErrorMessageInteraction() {
39 | defaultErrorBundle.getErrorMessage();
40 |
41 | verify(mockException).getMessage();
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/domain/src/test/java/com/fernandocejas/android10/sample/domain/interactor/GetUserDetailsTest.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (C) 2015 Fernando Cejas Open Source Project
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.fernandocejas.android10.sample.domain.interactor;
17 |
18 | import com.fernandocejas.android10.sample.domain.executor.PostExecutionThread;
19 | import com.fernandocejas.android10.sample.domain.executor.ThreadExecutor;
20 | import com.fernandocejas.android10.sample.domain.interactor.GetUserDetails.Params;
21 | import com.fernandocejas.android10.sample.domain.repository.UserRepository;
22 | import org.junit.Before;
23 | import org.junit.Rule;
24 | import org.junit.Test;
25 | import org.junit.rules.ExpectedException;
26 | import org.junit.runner.RunWith;
27 | import org.mockito.Mock;
28 | import org.mockito.runners.MockitoJUnitRunner;
29 |
30 | import static org.mockito.Mockito.verify;
31 | import static org.mockito.Mockito.verifyNoMoreInteractions;
32 | import static org.mockito.Mockito.verifyZeroInteractions;
33 |
34 | @RunWith(MockitoJUnitRunner.class)
35 | public class GetUserDetailsTest {
36 |
37 | private static final int USER_ID = 123;
38 |
39 | private GetUserDetails getUserDetails;
40 |
41 | @Mock private UserRepository mockUserRepository;
42 | @Mock private ThreadExecutor mockThreadExecutor;
43 | @Mock private PostExecutionThread mockPostExecutionThread;
44 |
45 | @Rule public ExpectedException expectedException = ExpectedException.none();
46 |
47 | @Before
48 | public void setUp() {
49 | getUserDetails = new GetUserDetails(mockUserRepository, mockThreadExecutor,
50 | mockPostExecutionThread);
51 | }
52 |
53 | @Test
54 | public void testGetUserDetailsUseCaseObservableHappyCase() {
55 | getUserDetails.buildUseCaseObservable(Params.forUser(USER_ID));
56 |
57 | verify(mockUserRepository).user(USER_ID);
58 | verifyNoMoreInteractions(mockUserRepository);
59 | verifyZeroInteractions(mockPostExecutionThread);
60 | verifyZeroInteractions(mockThreadExecutor);
61 | }
62 |
63 | @Test
64 | public void testShouldFailWhenNoOrEmptyParameters() {
65 | expectedException.expect(NullPointerException.class);
66 | getUserDetails.buildUseCaseObservable(null);
67 | }
68 | }
69 |
--------------------------------------------------------------------------------
/domain/src/test/java/com/fernandocejas/android10/sample/domain/interactor/GetUserListTest.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (C) 2015 Fernando Cejas Open Source Project
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.fernandocejas.android10.sample.domain.interactor;
17 |
18 | import com.fernandocejas.android10.sample.domain.executor.PostExecutionThread;
19 | import com.fernandocejas.android10.sample.domain.executor.ThreadExecutor;
20 | import com.fernandocejas.android10.sample.domain.repository.UserRepository;
21 | import org.junit.Before;
22 | import org.junit.Test;
23 | import org.junit.runner.RunWith;
24 | import org.mockito.Mock;
25 | import org.mockito.runners.MockitoJUnitRunner;
26 |
27 | import static org.mockito.Mockito.verify;
28 | import static org.mockito.Mockito.verifyNoMoreInteractions;
29 | import static org.mockito.Mockito.verifyZeroInteractions;
30 |
31 | @RunWith(MockitoJUnitRunner.class)
32 | public class GetUserListTest {
33 |
34 | private GetUserList getUserList;
35 |
36 | @Mock private ThreadExecutor mockThreadExecutor;
37 | @Mock private PostExecutionThread mockPostExecutionThread;
38 | @Mock private UserRepository mockUserRepository;
39 |
40 | @Before
41 | public void setUp() {
42 | getUserList = new GetUserList(mockUserRepository, mockThreadExecutor,
43 | mockPostExecutionThread);
44 | }
45 |
46 | @Test
47 | public void testGetUserListUseCaseObservableHappyCase() {
48 | getUserList.buildUseCaseObservable(null);
49 |
50 | verify(mockUserRepository).users();
51 | verifyNoMoreInteractions(mockUserRepository);
52 | verifyZeroInteractions(mockThreadExecutor);
53 | verifyZeroInteractions(mockPostExecutionThread);
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/domain/src/test/java/com/fernandocejas/android10/sample/domain/interactor/UseCaseTest.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (C) 2015 Fernando Cejas Open Source Project
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.fernandocejas.android10.sample.domain.interactor;
17 |
18 | import com.fernandocejas.android10.sample.domain.executor.PostExecutionThread;
19 | import com.fernandocejas.android10.sample.domain.executor.ThreadExecutor;
20 | import io.reactivex.Observable;
21 | import io.reactivex.observers.DisposableObserver;
22 | import io.reactivex.schedulers.TestScheduler;
23 | import org.junit.Before;
24 | import org.junit.Rule;
25 | import org.junit.Test;
26 | import org.junit.rules.ExpectedException;
27 | import org.junit.runner.RunWith;
28 | import org.mockito.Mock;
29 | import org.mockito.runners.MockitoJUnitRunner;
30 |
31 | import static org.assertj.core.api.Assertions.assertThat;
32 | import static org.mockito.BDDMockito.given;
33 |
34 | @RunWith(MockitoJUnitRunner.class)
35 | public class UseCaseTest {
36 |
37 | private UseCaseTestClass useCase;
38 |
39 | private TestDisposableObserver