diff --git a/app/build.gradle b/app/build.gradle index 8f43028..40fa051 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -27,6 +27,11 @@ dependencies { def lifecycle_version = "1.1.1" def daggerVersion = '2.19' def kotlinCoroutineVersion = '1.0.1' + def rxAndroidVersion = '2.1.0' + def rxJavaVersion = '2.2.3' + def retrofitVersion = '2.5.0' + def mockitoVersion = '2.23.4' + implementation fileTree(include: ['*.jar'], dir: 'libs') implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" @@ -40,12 +45,13 @@ dependencies { annotationProcessor "android.arch.persistence.room:compiler:$room_version" // Retrofit - implementation 'com.squareup.retrofit2:retrofit:2.5.0' - implementation 'com.squareup.retrofit2:converter-gson:2.5.0' + implementation "com.squareup.retrofit2:retrofit:${retrofitVersion}" + implementation "com.squareup.retrofit2:converter-gson:${retrofitVersion}" - //coroutines - implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:$kotlinCoroutineVersion" - implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$kotlinCoroutineVersion" + //RX + implementation "io.reactivex.rxjava2:rxandroid:${rxAndroidVersion}" + implementation "io.reactivex.rxjava2:rxjava:${rxJavaVersion}" + implementation "com.squareup.retrofit2:adapter-rxjava2:${retrofitVersion}" // Dagger 2 implementation "com.google.dagger:dagger:$daggerVersion" @@ -54,6 +60,7 @@ dependencies { testImplementation 'junit:junit:4.12' + testImplementation "org.mockito:mockito-core:${mockitoVersion}" androidTestImplementation 'com.android.support.test:runner:1.0.2' androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2' implementation 'com.android.support:design:28.0.0' diff --git a/app/src/main/java/com/juanocampo/mytaxy/test/model/IRepository.kt b/app/src/main/java/com/juanocampo/mytaxy/test/model/IRepository.kt index 624f1d7..fd74744 100644 --- a/app/src/main/java/com/juanocampo/mytaxy/test/model/IRepository.kt +++ b/app/src/main/java/com/juanocampo/mytaxy/test/model/IRepository.kt @@ -1,10 +1,13 @@ package com.juanocampo.mytaxy.test.model +import com.google.android.gms.maps.model.LatLng import com.juanocampo.mytaxy.test.model.domain.Resource import com.juanocampo.mytaxy.test.model.domain.Taxi +import io.reactivex.Observable + interface IRepository { - suspend fun requestTaxisByLocation(p1Lat: Double, p1Lon: Double, p2Lat: Double, p2Lon: Double): Resource> + fun requestTaxisByLocation(p1Lat: Double, p1Lon: Double, p2Lat: Double, p2Lon: Double): Observable>> } \ No newline at end of file diff --git a/app/src/main/java/com/juanocampo/mytaxy/test/model/Repository.kt b/app/src/main/java/com/juanocampo/mytaxy/test/model/Repository.kt index e70dd75..5efdf1b 100644 --- a/app/src/main/java/com/juanocampo/mytaxy/test/model/Repository.kt +++ b/app/src/main/java/com/juanocampo/mytaxy/test/model/Repository.kt @@ -1,50 +1,38 @@ package com.juanocampo.mytaxy.test.model +import com.google.android.gms.maps.model.LatLng import com.juanocampo.mytaxy.test.model.domain.Resource import com.juanocampo.mytaxy.test.model.domain.Taxi import com.juanocampo.mytaxy.test.model.source.remote.IRemoteDataSource import com.juanocampo.mytaxy.test.model.source.remote.mapper.TaxiMapper -import kotlinx.coroutines.CoroutineDispatcher -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.withContext +import io.reactivex.Observable class Repository( private val iRemoteDataSource: IRemoteDataSource, - private val iMapper: TaxiMapper, - private val ioDispatcher: CoroutineDispatcher = Dispatchers.IO + private val taxiResponseMapper: TaxiMapper ) : IRepository { - override suspend fun requestTaxisByLocation( + override fun requestTaxisByLocation( p1Lat: Double, p1Lon: Double, p2Lat: Double, p2Lon: Double - ): Resource> { - return withContext(ioDispatcher) { - return@withContext fetchTaxisFromRemote( - p1Lat, - p1Lon, - p2Lat, - p2Lon - ) - } - } + ): Observable>> { - private fun fetchTaxisFromRemote( - p1Lat: Double, p1Lon: Double, p2Lat: Double, p2Lon: Double - ): Resource> { - return try { - val fetchedItems = iRemoteDataSource.fetchTaxisByLocation( - p1Lat, - p1Lon, - p2Lat, - p2Lon - ) - if (fetchedItems.isNullOrEmpty()) { - Resource.error("could not load info, try later") - } else { - val mappedItems = iMapper.mapResponseToAppModel(fetchedItems) - Resource.success(mappedItems) - } - } catch (e: Exception) { - Resource.error(e.message ?: "Something went wrong ") + return iRemoteDataSource.fetchTaxisByLocation( + p1Lat, + p1Lon, + p2Lat, + p2Lon + ).toObservable() + .map(taxiResponseMapper) + .map {listItems -> + return@map if (listItems.isNullOrEmpty()) { + Resource.error("could not load info, try later") + } else { + val mapItems: HashMap = HashMap() + listItems.forEach { + mapItems[it.latLong] = it + } + Resource.success(mapItems) + } } } } \ No newline at end of file diff --git a/app/src/main/java/com/juanocampo/mytaxy/test/model/di/RepositoryModule.kt b/app/src/main/java/com/juanocampo/mytaxy/test/model/di/RepositoryModule.kt index 2234ba3..ce533a0 100644 --- a/app/src/main/java/com/juanocampo/mytaxy/test/model/di/RepositoryModule.kt +++ b/app/src/main/java/com/juanocampo/mytaxy/test/model/di/RepositoryModule.kt @@ -10,6 +10,7 @@ import com.juanocampo.mytaxy.test.model.source.remote.service.TaxiApi import dagger.Module import dagger.Provides import retrofit2.Retrofit +import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory import retrofit2.converter.gson.GsonConverterFactory @@ -22,6 +23,8 @@ class RepositoryModule { val builder: Retrofit.Builder = Retrofit.Builder() .baseUrl("https://fake-poi-api.mytaxi.com/") .addConverterFactory(GsonConverterFactory.create()) + .addCallAdapterFactory(RxJava2CallAdapterFactory.create()) + val retrofit = builder.build() return retrofit.create(TaxiApi::class.java) diff --git a/app/src/main/java/com/juanocampo/mytaxy/test/model/source/remote/IRemoteDataSource.kt b/app/src/main/java/com/juanocampo/mytaxy/test/model/source/remote/IRemoteDataSource.kt index ebff057..dfef906 100644 --- a/app/src/main/java/com/juanocampo/mytaxy/test/model/source/remote/IRemoteDataSource.kt +++ b/app/src/main/java/com/juanocampo/mytaxy/test/model/source/remote/IRemoteDataSource.kt @@ -1,8 +1,9 @@ package com.juanocampo.mytaxy.test.model.source.remote import com.juanocampo.mytaxy.test.model.source.remote.domain.TaxiResponse +import io.reactivex.Single interface IRemoteDataSource { - fun fetchTaxisByLocation(p1Lat: Double, p1Lon: Double, p2Lat: Double, p2Lon: Double): List + fun fetchTaxisByLocation(p1Lat: Double, p1Lon: Double, p2Lat: Double, p2Lon: Double):Single> } \ No newline at end of file diff --git a/app/src/main/java/com/juanocampo/mytaxy/test/model/source/remote/RemoteDataSource.kt b/app/src/main/java/com/juanocampo/mytaxy/test/model/source/remote/RemoteDataSource.kt index 973f1ca..32cae70 100644 --- a/app/src/main/java/com/juanocampo/mytaxy/test/model/source/remote/RemoteDataSource.kt +++ b/app/src/main/java/com/juanocampo/mytaxy/test/model/source/remote/RemoteDataSource.kt @@ -2,17 +2,13 @@ package com.juanocampo.mytaxy.test.model.source.remote import com.juanocampo.mytaxy.test.model.source.remote.domain.TaxiResponse import com.juanocampo.mytaxy.test.model.source.remote.service.TaxiApi - +import io.reactivex.Single class RemoteDataSource(private val api: TaxiApi): IRemoteDataSource { - override fun fetchTaxisByLocation(p1Lat: Double, p1Lon: Double, p2Lat: Double, p2Lon: Double): List { - val request = api.fetchTaxisByLocation(p1Lat = p1Lat.toString(), p1Lon = p1Lon.toString(), p2Lat = p2Lat.toString(), p2Lon = p2Lon.toString()) - val apiResponse = request.execute() - return if (apiResponse.isSuccessful && apiResponse.body()?.poiList != null) { - apiResponse.body()?.poiList!! - } else { - emptyList() + override fun fetchTaxisByLocation(p1Lat: Double, p1Lon: Double, p2Lat: Double, p2Lon: Double): Single> { + return api.fetchTaxisByLocation(p1Lat = p1Lat.toString(), p1Lon = p1Lon.toString(), p2Lat = p2Lat.toString(), p2Lon = p2Lon.toString()).map { + return@map it.poiList ?: emptyList() } } diff --git a/app/src/main/java/com/juanocampo/mytaxy/test/model/source/remote/mapper/IMapper.kt b/app/src/main/java/com/juanocampo/mytaxy/test/model/source/remote/mapper/IMapper.kt deleted file mode 100644 index 2407cf9..0000000 --- a/app/src/main/java/com/juanocampo/mytaxy/test/model/source/remote/mapper/IMapper.kt +++ /dev/null @@ -1,5 +0,0 @@ -package com.juanocampo.mytaxy.test.model.source.remote.mapper - -interface IMapper { - fun mapResponseToAppModel(toParse: R) : T -} \ No newline at end of file diff --git a/app/src/main/java/com/juanocampo/mytaxy/test/model/source/remote/mapper/TaxiMapper.kt b/app/src/main/java/com/juanocampo/mytaxy/test/model/source/remote/mapper/TaxiMapper.kt index b80160b..825dda9 100644 --- a/app/src/main/java/com/juanocampo/mytaxy/test/model/source/remote/mapper/TaxiMapper.kt +++ b/app/src/main/java/com/juanocampo/mytaxy/test/model/source/remote/mapper/TaxiMapper.kt @@ -2,14 +2,20 @@ package com.juanocampo.mytaxy.test.model.source.remote.mapper import com.juanocampo.mytaxy.test.model.domain.Taxi import com.juanocampo.mytaxy.test.model.source.remote.domain.TaxiResponse +import io.reactivex.functions.Function -class TaxiMapper: IMapper, List> { +class TaxiMapper: Function, List> { - override fun mapResponseToAppModel(toParse: List): List { + + override fun apply(toParse: List): List { + if (toParse.isNullOrEmpty()) { + return emptyList() + } val list = ArrayList() toParse.forEach { list.add(it.toTaxi()) } return list } + } \ No newline at end of file diff --git a/app/src/main/java/com/juanocampo/mytaxy/test/model/source/remote/service/TaxiApi.kt b/app/src/main/java/com/juanocampo/mytaxy/test/model/source/remote/service/TaxiApi.kt index 450bdc6..808fc9c 100644 --- a/app/src/main/java/com/juanocampo/mytaxy/test/model/source/remote/service/TaxiApi.kt +++ b/app/src/main/java/com/juanocampo/mytaxy/test/model/source/remote/service/TaxiApi.kt @@ -1,7 +1,7 @@ package com.juanocampo.mytaxy.test.model.source.remote.service import com.juanocampo.mytaxy.test.model.source.remote.domain.TaxiApiResponse -import retrofit2.Call +import io.reactivex.Single import retrofit2.http.GET import retrofit2.http.Query @@ -11,5 +11,5 @@ interface TaxiApi { fun fetchTaxisByLocation(@Query("p1Lat") p1Lat: String, @Query("p1Lon") p1Lon: String, @Query("p2Lat") p2Lat: String, - @Query("p2Lon") p2Lon: String): Call + @Query("p2Lon") p2Lon: String): Single } \ No newline at end of file diff --git a/app/src/main/java/com/juanocampo/mytaxy/test/view/fragment/TaxisListFragment.kt b/app/src/main/java/com/juanocampo/mytaxy/test/view/fragment/TaxisListFragment.kt index 95d9056..6d5dc0d 100644 --- a/app/src/main/java/com/juanocampo/mytaxy/test/view/fragment/TaxisListFragment.kt +++ b/app/src/main/java/com/juanocampo/mytaxy/test/view/fragment/TaxisListFragment.kt @@ -6,7 +6,6 @@ import android.os.Bundle import android.support.v4.app.Fragment import android.support.v7.widget.LinearLayoutManager import android.support.v7.widget.LinearSnapHelper -import android.support.v7.widget.RecyclerView import android.view.LayoutInflater import android.view.View import android.view.ViewGroup @@ -14,6 +13,7 @@ import android.widget.Toast import com.juanocampo.mytaxy.test.R import com.juanocampo.mytaxy.test.di.AndroidInjectorUtils import com.juanocampo.mytaxy.test.model.domain.Taxi +import com.juanocampo.mytaxy.test.utils.delegate.model.RecyclerViewType import com.juanocampo.mytaxy.test.view.adapter.TaxiAdapter import com.juanocampo.mytaxy.test.view.adapter.TaxiDelegateAdapter import com.juanocampo.mytaxy.test.viewmodel.TaxiViewModel @@ -54,8 +54,8 @@ class TaxisListFragment: Fragment(), TaxiDelegateAdapter.OnItemListListener { Toast.makeText(context, error, Toast.LENGTH_SHORT).show() }) - viewModel.getRequestListObserver().observe(this, Observer { - taxList.smoothScrollToPosition(adapter.items.indexOf(it)) + viewModel.getRequestListObserver().observe(this, Observer {taxi -> + taxList.smoothScrollToPosition(adapter.items.indexOf(taxi as RecyclerViewType)) }) } diff --git a/app/src/main/java/com/juanocampo/mytaxy/test/viewmodel/TaxiViewModel.kt b/app/src/main/java/com/juanocampo/mytaxy/test/viewmodel/TaxiViewModel.kt index 0ff43e5..a6b4231 100644 --- a/app/src/main/java/com/juanocampo/mytaxy/test/viewmodel/TaxiViewModel.kt +++ b/app/src/main/java/com/juanocampo/mytaxy/test/viewmodel/TaxiViewModel.kt @@ -6,29 +6,25 @@ import android.arch.lifecycle.MutableLiveData import android.arch.lifecycle.Transformations import android.arch.lifecycle.ViewModel import android.support.annotation.UiThread -import android.support.annotation.WorkerThread import com.google.android.gms.maps.model.LatLng import com.juanocampo.mytaxy.test.model.IRepository -import com.juanocampo.mytaxy.test.model.domain.Resource import com.juanocampo.mytaxy.test.model.domain.Status import com.juanocampo.mytaxy.test.model.domain.Taxi -import com.juanocampo.mytaxy.test.utils.delegate.model.RecyclerViewType -import kotlinx.coroutines.* +import io.reactivex.android.schedulers.AndroidSchedulers +import io.reactivex.disposables.Disposable +import io.reactivex.schedulers.Schedulers -class TaxiViewModel(private val iRepository: IRepository, - private val mainDispatcher: CoroutineDispatcher = Dispatchers.Main, - private val ioDispatcher: CoroutineDispatcher = Dispatchers.IO): ViewModel() { +class TaxiViewModel(private val iRepository: IRepository) : ViewModel() { val errorLiveData = MutableLiveData() - val taxiMapLiveData = MutableLiveData>() + val taxiMapLiveData = MutableLiveData>() private val mapClickedLivedData = MutableLiveData() - private val itemCLickedLiveData = MutableLiveData() - private val requestListFocusLiveData: LiveData + private val itemCLickedLiveData = MutableLiveData() + private val requestListFocusLiveData: LiveData private val requestMapFocusLiveData: LiveData - private var isLoading = false - private val mapItems: HashMap = HashMap() + private var mapItems: HashMap = HashMap() init { requestListFocusLiveData = Transformations.map(mapClickedLivedData, Function { @@ -40,73 +36,52 @@ class TaxiViewModel(private val iRepository: IRepository, }) } - fun fetchTaxisByLocationPage(p1Lat: Double, p1Lon: Double, p2Lat: Double, p2Lon: Double) { - GlobalScope.launch(ioDispatcher) { - syncRepository(p1Lat, - p1Lon, - p2Lat, - p2Lon) - } - } - - @Synchronized - @WorkerThread - private suspend fun syncRepository(p1Lat: Double, p1Lon: Double, p2Lat: Double, p2Lon: Double) { - if (!isLoading) { - isLoading = true + private var disposable: Disposable? = null - val response = iRepository.requestTaxisByLocation(p1Lat, - p1Lon, - p2Lat, - p2Lon) + fun fetchTaxisByLocationPage(p1Lat: Double, p1Lon: Double, p2Lat: Double, p2Lon: Double) { + disposable = iRepository.requestTaxisByLocation( + p1Lat, + p1Lon, + p2Lat, + p2Lon + ).subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()) + .subscribe({ response -> when { response.status == Status.SUCCESS -> { - handleSuccessCase(response) + response.info?.let { + mapItems = response.info + publishUIResults(taxiMapLiveData, mapItems) + } } - response.status == Status.LOADING -> isLoading = true - else -> { - handleErrorCase(response) + handleErrorCase(response.message) } } - } - } - @WorkerThread - private suspend fun handleSuccessCase(response: Resource>) { - isLoading = false - response.info?.let { - addItemsAndNotify(it) - } + }, { + handleErrorCase(it.message ?: "Something when wrong, please try later") + }) } - @WorkerThread - private suspend fun handleErrorCase(response: Resource>) { - isLoading = false - publishUIResults(errorLiveData, response.message) + override fun onCleared() { + super.onCleared() + disposable?.dispose() } - @WorkerThread - private suspend fun addItemsAndNotify(itemsToAdd: List) { - itemsToAdd.forEach { - if (it is Taxi) { - mapItems[it.latLong] = it - } - } - publishUIResults(taxiMapLiveData, mapItems) + private fun handleErrorCase(message: String) { + publishUIResults(errorLiveData, message) } @UiThread - private suspend fun publishUIResults(liveData: MutableLiveData, data: T) { - withContext(mainDispatcher) { - liveData.value = data - } + private fun publishUIResults(liveData: MutableLiveData, data: T) { + liveData.value = data } @UiThread fun setClickedMarker(latLng: LatLng) { mapClickedLivedData.value = latLng } + @UiThread fun setClickedItem(taxi: Taxi) { itemCLickedLiveData.value = taxi diff --git a/app/src/test/java/com/juanocampo/mytaxy/test/model/RepositoryTest.kt b/app/src/test/java/com/juanocampo/mytaxy/test/model/RepositoryTest.kt new file mode 100644 index 0000000..6872ff3 --- /dev/null +++ b/app/src/test/java/com/juanocampo/mytaxy/test/model/RepositoryTest.kt @@ -0,0 +1,67 @@ +package com.juanocampo.mytaxy.test.model + +import com.google.android.gms.maps.model.LatLng +import com.juanocampo.mytaxy.test.model.domain.Resource +import com.juanocampo.mytaxy.test.model.domain.Status +import com.juanocampo.mytaxy.test.model.domain.Taxi +import com.juanocampo.mytaxy.test.model.source.remote.IRemoteDataSource +import com.juanocampo.mytaxy.test.model.source.remote.domain.Coordinate +import com.juanocampo.mytaxy.test.model.source.remote.domain.TaxiResponse +import com.juanocampo.mytaxy.test.model.source.remote.mapper.TaxiMapper +import io.reactivex.Single +import io.reactivex.android.plugins.RxAndroidPlugins +import io.reactivex.functions.Predicate +import io.reactivex.observers.TestObserver +import io.reactivex.schedulers.Schedulers +import org.junit.Before +import org.junit.Test + +import org.mockito.Mock +import org.mockito.Mockito +import org.mockito.MockitoAnnotations + +class RepositoryTest { + + @Mock + lateinit var iRemoteDataSource: IRemoteDataSource + + lateinit var taxiResponseMapper: TaxiMapper + + lateinit var repository: Repository + + @Before + fun setUp() { + RxAndroidPlugins.setInitMainThreadSchedulerHandler { Schedulers.trampoline() } + MockitoAnnotations.initMocks(this) + taxiResponseMapper = TaxiMapper() + repository = Repository(iRemoteDataSource, taxiResponseMapper) + } + + @Test + fun `requestTaxisByLocation with an empty list will return a resource error`() { + Mockito.`when`(iRemoteDataSource.fetchTaxisByLocation(0.0, 0.0, 0.0, 0.0)).thenReturn(Single.just(emptyList())) + val testObserver = TestObserver>>() + repository.requestTaxisByLocation(0.0, 0.0, 0.0, 0.0).subscribe(testObserver) + testObserver.assertValueAt(0, Predicate { return@Predicate it.status == Status.ERROR }) + testObserver.assertValueAt(0, Predicate { return@Predicate it.message == "could not load info, try later" }) + } + + + @Test + fun `requestTaxisByLocation with a valid response list will map a success`() { + val taxiResponseList = ArrayList() + val taxiItem = TaxiResponse(1, Coordinate(0.0,0.0)) + taxiResponseList.add(taxiItem) + Mockito.`when`(iRemoteDataSource.fetchTaxisByLocation(0.0, 0.0, 0.0, 0.0)).thenReturn(Single.just(taxiResponseList)) + val testObserver = TestObserver>>() + repository.requestTaxisByLocation(0.0, 0.0, 0.0, 0.0).subscribe(testObserver) + testObserver.assertValueAt(0, Predicate { return@Predicate it.status == Status.SUCCESS }) + testObserver.assertValueAt(0, Predicate { return@Predicate it.info?.size == 1 }) + testObserver.assertValueAt(0, Predicate { return@Predicate ArrayList(it.info?.entries)[0].key.longitude == taxiItem.coordinate?.longitude}) + testObserver.assertValueAt(0, Predicate { return@Predicate ArrayList(it.info?.entries)[0].key.latitude == taxiItem.coordinate?.latitude}) + + testObserver.assertValueAt(0, Predicate { return@Predicate ArrayList(it.info?.values)[0].id == taxiItem.id}) + testObserver.assertValueAt(0, Predicate { return@Predicate ArrayList(it.info?.values)[0].latLong.latitude == taxiItem?.coordinate?.latitude}) + testObserver.assertValueAt(0, Predicate { return@Predicate ArrayList(it.info?.values)[0].latLong.longitude == taxiItem.coordinate?.longitude}) + } +} \ No newline at end of file diff --git a/app/src/test/java/com/juanocampo/mytaxy/test/model/source/remote/RemoteDataSourceTest.kt b/app/src/test/java/com/juanocampo/mytaxy/test/model/source/remote/RemoteDataSourceTest.kt new file mode 100644 index 0000000..d559255 --- /dev/null +++ b/app/src/test/java/com/juanocampo/mytaxy/test/model/source/remote/RemoteDataSourceTest.kt @@ -0,0 +1,67 @@ +package com.juanocampo.mytaxy.test.model.source.remote + +import com.juanocampo.mytaxy.test.model.source.remote.domain.TaxiApiResponse +import com.juanocampo.mytaxy.test.model.source.remote.domain.TaxiResponse +import com.juanocampo.mytaxy.test.model.source.remote.service.TaxiApi +import io.reactivex.Single +import io.reactivex.android.plugins.RxAndroidPlugins +import io.reactivex.functions.Predicate +import io.reactivex.observers.TestObserver +import io.reactivex.schedulers.Schedulers +import org.junit.Before +import org.junit.Test + +import org.junit.Rule +import org.junit.rules.ExpectedException +import org.mockito.Mock +import org.mockito.Mockito.verify +import org.mockito.MockitoAnnotations +import org.mockito.Mockito.`when` as whenever + +class RemoteDataSourceTest { + + @Mock + lateinit var taxiApi: TaxiApi + + lateinit var remoteDataSource: RemoteDataSource + + + @get:Rule + val exception: ExpectedException = ExpectedException.none() + + @Before + fun setUp() { + RxAndroidPlugins.setInitMainThreadSchedulerHandler { Schedulers.trampoline() } + MockitoAnnotations.initMocks(this) + remoteDataSource = RemoteDataSource(taxiApi) + } + + @Test + fun `fetchTaxisByLocation with an empty poiList list will return empty TaxiResponse List`() { + var taxiResponse = TaxiApiResponse(null) + whenever(taxiApi.fetchTaxisByLocation("0.0", "0.0", "0.0", "0.0")).thenReturn(Single.just(taxiResponse)) + val testObserver = TestObserver>() + + remoteDataSource.fetchTaxisByLocation(0.0, 0.0, 0.0, 0.0).toObservable().subscribe(testObserver) + + verify(taxiApi).fetchTaxisByLocation("0.0", "0.0", "0.0", "0.0") + testObserver.assertValueAt(0, Predicate { return@Predicate it.isNullOrEmpty() }) + testObserver.assertComplete() + } + + @Test + fun `fetchTaxisByLocation with an empty poiList list will return valid TaxiResponse List`() { + val poiList = ArrayList() + poiList.add(TaxiResponse(0, null)) + var taxiResponse = TaxiApiResponse(poiList) + + whenever(taxiApi.fetchTaxisByLocation("0.0", "0.0", "0.0", "0.0")).thenReturn(Single.just(taxiResponse)) + val testObserver = TestObserver>() + + remoteDataSource.fetchTaxisByLocation(0.0, 0.0, 0.0, 0.0).toObservable().subscribe(testObserver) + + verify(taxiApi).fetchTaxisByLocation("0.0", "0.0", "0.0", "0.0") + testObserver.assertValueAt(0, poiList) + testObserver.assertComplete() + } +} \ No newline at end of file