mirror of
				https://github.com/KokaKiwi/BarInsta
				synced 2025-11-04 05:25:35 +00:00 
			
		
		
		
	Add some ProfileFragmentViewModel logic and tests
This commit is contained in:
		
							parent
							
								
									1d9eb43442
								
							
						
					
					
						commit
						70ffac3025
					
				@ -242,9 +242,10 @@ dependencies {
 | 
				
			|||||||
    testImplementation 'org.junit.jupiter:junit-jupiter:5.7.2'
 | 
					    testImplementation 'org.junit.jupiter:junit-jupiter:5.7.2'
 | 
				
			||||||
    testImplementation "androidx.test.ext:junit-ktx:1.1.2"
 | 
					    testImplementation "androidx.test.ext:junit-ktx:1.1.2"
 | 
				
			||||||
    testImplementation "androidx.test:core-ktx:1.3.0"
 | 
					    testImplementation "androidx.test:core-ktx:1.3.0"
 | 
				
			||||||
 | 
					    testImplementation "androidx.arch.core:core-testing:2.1.0"
 | 
				
			||||||
    testImplementation "org.robolectric:robolectric:4.5.1"
 | 
					    testImplementation "org.robolectric:robolectric:4.5.1"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    androidTestImplementation 'org.junit.jupiter:junit-jupiter:5.7.1'
 | 
					    androidTestImplementation 'org.junit.jupiter:junit-jupiter:5.7.2'
 | 
				
			||||||
    androidTestImplementation 'androidx.test:core:1.3.0'
 | 
					    androidTestImplementation 'androidx.test:core:1.3.0'
 | 
				
			||||||
    androidTestImplementation 'com.android.support:support-annotations:28.0.0'
 | 
					    androidTestImplementation 'com.android.support:support-annotations:28.0.0'
 | 
				
			||||||
    androidTestImplementation 'com.android.support.test:runner:1.0.2'
 | 
					    androidTestImplementation 'com.android.support.test:runner:1.0.2'
 | 
				
			||||||
 | 
				
			|||||||
@ -382,7 +382,7 @@ public class ProfileFragment extends Fragment implements SwipeRefreshLayout.OnRe
 | 
				
			|||||||
            shouldRefresh = false;
 | 
					            shouldRefresh = false;
 | 
				
			||||||
            return root;
 | 
					            return root;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        // appStateViewModel.getCurrentUserLiveData().observe(getViewLifecycleOwner(), user -> viewModel.setCurrentUser(user));
 | 
					        appStateViewModel.getCurrentUserLiveData().observe(getViewLifecycleOwner(), user -> viewModel.setCurrentUser(user));
 | 
				
			||||||
        binding = FragmentProfileBinding.inflate(inflater, container, false);
 | 
					        binding = FragmentProfileBinding.inflate(inflater, container, false);
 | 
				
			||||||
        root = binding.getRoot();
 | 
					        root = binding.getRoot();
 | 
				
			||||||
        profileDetailsBinding = binding.header;
 | 
					        profileDetailsBinding = binding.header;
 | 
				
			||||||
 | 
				
			|||||||
@ -1,13 +1,12 @@
 | 
				
			|||||||
package awais.instagrabber.viewmodels
 | 
					package awais.instagrabber.viewmodels
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import android.os.Bundle
 | 
					import android.os.Bundle
 | 
				
			||||||
import android.util.Log
 | 
					 | 
				
			||||||
import androidx.lifecycle.*
 | 
					import androidx.lifecycle.*
 | 
				
			||||||
import androidx.savedstate.SavedStateRegistryOwner
 | 
					import androidx.savedstate.SavedStateRegistryOwner
 | 
				
			||||||
import awais.instagrabber.db.repositories.AccountRepository
 | 
					import awais.instagrabber.db.repositories.AccountRepository
 | 
				
			||||||
import awais.instagrabber.db.repositories.FavoriteRepository
 | 
					import awais.instagrabber.db.repositories.FavoriteRepository
 | 
				
			||||||
 | 
					import awais.instagrabber.models.Resource
 | 
				
			||||||
import awais.instagrabber.repositories.responses.User
 | 
					import awais.instagrabber.repositories.responses.User
 | 
				
			||||||
import awais.instagrabber.utils.extensions.TAG
 | 
					 | 
				
			||||||
import awais.instagrabber.webservices.*
 | 
					import awais.instagrabber.webservices.*
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class ProfileFragmentViewModel(
 | 
					class ProfileFragmentViewModel(
 | 
				
			||||||
@ -20,17 +19,44 @@ class ProfileFragmentViewModel(
 | 
				
			|||||||
    accountRepository: AccountRepository,
 | 
					    accountRepository: AccountRepository,
 | 
				
			||||||
    favoriteRepository: FavoriteRepository,
 | 
					    favoriteRepository: FavoriteRepository,
 | 
				
			||||||
) : ViewModel() {
 | 
					) : ViewModel() {
 | 
				
			||||||
    private val _profile = MutableLiveData<User?>()
 | 
					    private val _profile = MutableLiveData<Resource<User?>>(Resource.loading(null))
 | 
				
			||||||
    val profile: LiveData<User?> = _profile
 | 
					    private val _isLoggedIn = MutableLiveData(false)
 | 
				
			||||||
    val username: LiveData<String> = Transformations.map(profile) { return@map it?.username ?: "" }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    var currentUser: User? = null
 | 
					    val profile: LiveData<Resource<User?>> = _profile
 | 
				
			||||||
    var isLoggedIn = false
 | 
					
 | 
				
			||||||
        get() = currentUser != null
 | 
					    /**
 | 
				
			||||||
        private set
 | 
					     * Username of profile without '`@`'
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    val username: LiveData<String> = Transformations.map(profile) {
 | 
				
			||||||
 | 
					        return@map when (it.status) {
 | 
				
			||||||
 | 
					            Resource.Status.LOADING, Resource.Status.ERROR -> ""
 | 
				
			||||||
 | 
					            Resource.Status.SUCCESS -> it.data?.username ?: ""
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    val isLoggedIn: LiveData<Boolean> = _isLoggedIn
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    var currentUser: Resource<User?>? = null
 | 
				
			||||||
 | 
					        set(value) {
 | 
				
			||||||
 | 
					            _isLoggedIn.postValue(value?.data != null)
 | 
				
			||||||
 | 
					            // if no profile, and value is valid, set it as profile
 | 
				
			||||||
 | 
					            val profileValue = profile.value
 | 
				
			||||||
 | 
					            if (
 | 
				
			||||||
 | 
					                profileValue?.status != Resource.Status.LOADING
 | 
				
			||||||
 | 
					                && profileValue?.data == null
 | 
				
			||||||
 | 
					                && value?.status == Resource.Status.SUCCESS
 | 
				
			||||||
 | 
					                && value.data != null
 | 
				
			||||||
 | 
					            ) {
 | 
				
			||||||
 | 
					                _profile.postValue(Resource.success(value.data))
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            field = value
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    init {
 | 
					    init {
 | 
				
			||||||
        Log.d(TAG, "${state.keys()} $userRepository $friendshipRepository $storiesRepository $mediaRepository")
 | 
					        // Log.d(TAG, "${state.keys()} $userRepository $friendshipRepository $storiesRepository $mediaRepository")
 | 
				
			||||||
 | 
					        val usernameFromState = state.get<String?>("username")
 | 
				
			||||||
 | 
					        if (usernameFromState.isNullOrBlank()) {
 | 
				
			||||||
 | 
					            _profile.postValue(Resource.success(null))
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										41
									
								
								app/src/test/java/awais/instagrabber/LiveDataTestUtil.kt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										41
									
								
								app/src/test/java/awais/instagrabber/LiveDataTestUtil.kt
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,41 @@
 | 
				
			|||||||
 | 
					package awais.instagrabber
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import androidx.annotation.VisibleForTesting
 | 
				
			||||||
 | 
					import androidx.lifecycle.LiveData
 | 
				
			||||||
 | 
					import androidx.lifecycle.Observer
 | 
				
			||||||
 | 
					import java.util.concurrent.CountDownLatch
 | 
				
			||||||
 | 
					import java.util.concurrent.TimeUnit
 | 
				
			||||||
 | 
					import java.util.concurrent.TimeoutException
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@VisibleForTesting(otherwise = VisibleForTesting.NONE)
 | 
				
			||||||
 | 
					fun <T> LiveData<T>.getOrAwaitValue(
 | 
				
			||||||
 | 
					    time: Long = 2,
 | 
				
			||||||
 | 
					    timeUnit: TimeUnit = TimeUnit.SECONDS,
 | 
				
			||||||
 | 
					    afterObserve: () -> Unit = {}
 | 
				
			||||||
 | 
					): T {
 | 
				
			||||||
 | 
					    var data: T? = null
 | 
				
			||||||
 | 
					    val latch = CountDownLatch(1)
 | 
				
			||||||
 | 
					    val observer = object : Observer<T> {
 | 
				
			||||||
 | 
					        override fun onChanged(o: T?) {
 | 
				
			||||||
 | 
					            data = o
 | 
				
			||||||
 | 
					            latch.countDown()
 | 
				
			||||||
 | 
					            this@getOrAwaitValue.removeObserver(this)
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    this.observeForever(observer)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    try {
 | 
				
			||||||
 | 
					        afterObserve.invoke()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Don't wait indefinitely if the LiveData is not set.
 | 
				
			||||||
 | 
					        if (!latch.await(time, timeUnit)) {
 | 
				
			||||||
 | 
					            throw TimeoutException("LiveData value was never set.")
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    } finally {
 | 
				
			||||||
 | 
					        this.removeObserver(observer)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Suppress("UNCHECKED_CAST")
 | 
				
			||||||
 | 
					    return data as T
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -1,5 +1,6 @@
 | 
				
			|||||||
package awais.instagrabber.viewmodels
 | 
					package awais.instagrabber.viewmodels
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import androidx.arch.core.executor.testing.InstantTaskExecutorRule
 | 
				
			||||||
import androidx.lifecycle.SavedStateHandle
 | 
					import androidx.lifecycle.SavedStateHandle
 | 
				
			||||||
import androidx.test.ext.junit.runners.AndroidJUnit4
 | 
					import androidx.test.ext.junit.runners.AndroidJUnit4
 | 
				
			||||||
import awais.instagrabber.common.*
 | 
					import awais.instagrabber.common.*
 | 
				
			||||||
@ -7,19 +8,49 @@ import awais.instagrabber.db.datasources.AccountDataSource
 | 
				
			|||||||
import awais.instagrabber.db.datasources.FavoriteDataSource
 | 
					import awais.instagrabber.db.datasources.FavoriteDataSource
 | 
				
			||||||
import awais.instagrabber.db.repositories.AccountRepository
 | 
					import awais.instagrabber.db.repositories.AccountRepository
 | 
				
			||||||
import awais.instagrabber.db.repositories.FavoriteRepository
 | 
					import awais.instagrabber.db.repositories.FavoriteRepository
 | 
				
			||||||
 | 
					import awais.instagrabber.getOrAwaitValue
 | 
				
			||||||
 | 
					import awais.instagrabber.models.Resource
 | 
				
			||||||
 | 
					import awais.instagrabber.repositories.responses.User
 | 
				
			||||||
import awais.instagrabber.webservices.*
 | 
					import awais.instagrabber.webservices.*
 | 
				
			||||||
 | 
					import org.junit.Rule
 | 
				
			||||||
import org.junit.Test
 | 
					import org.junit.Test
 | 
				
			||||||
 | 
					import org.junit.jupiter.api.Assertions.assertEquals
 | 
				
			||||||
 | 
					import org.junit.jupiter.api.Assertions.assertNull
 | 
				
			||||||
import org.junit.runner.RunWith
 | 
					import org.junit.runner.RunWith
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@RunWith(AndroidJUnit4::class)
 | 
					@RunWith(AndroidJUnit4::class)
 | 
				
			||||||
internal class ProfileFragmentViewModelTest {
 | 
					internal class ProfileFragmentViewModelTest {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @get:Rule
 | 
				
			||||||
 | 
					    var instantExecutorRule = InstantTaskExecutorRule()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @Test
 | 
					    @Test
 | 
				
			||||||
    fun testNoUsernameNoCurrentUser() {
 | 
					    fun testNoUsernameNoCurrentUser() {
 | 
				
			||||||
        val state = SavedStateHandle(
 | 
					        val accountDataSource = AccountDataSource(AccountDaoAdapter())
 | 
				
			||||||
            mutableMapOf<String, Any>(
 | 
					        val viewModel = ProfileFragmentViewModel(
 | 
				
			||||||
                "username" to ""
 | 
					            SavedStateHandle(),
 | 
				
			||||||
            )
 | 
					            UserRepository(UserServiceAdapter()),
 | 
				
			||||||
 | 
					            FriendshipRepository(FriendshipServiceAdapter()),
 | 
				
			||||||
 | 
					            StoriesRepository(StoriesServiceAdapter()),
 | 
				
			||||||
 | 
					            MediaRepository(MediaServiceAdapter()),
 | 
				
			||||||
 | 
					            GraphQLRepository(GraphQLServiceAdapter()),
 | 
				
			||||||
 | 
					            AccountRepository(accountDataSource),
 | 
				
			||||||
 | 
					            FavoriteRepository(FavoriteDataSource(FavoriteDaoAdapter()))
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
 | 
					        assertEquals(false, viewModel.isLoggedIn.getOrAwaitValue())
 | 
				
			||||||
 | 
					        assertNull(viewModel.profile.getOrAwaitValue().data)
 | 
				
			||||||
 | 
					        assertEquals("", viewModel.username.getOrAwaitValue())
 | 
				
			||||||
 | 
					        viewModel.currentUser = Resource.success(null)
 | 
				
			||||||
 | 
					        assertEquals(false, viewModel.isLoggedIn.getOrAwaitValue())
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Test
 | 
				
			||||||
 | 
					    fun testNoUsernameWithCurrentUser() {
 | 
				
			||||||
 | 
					        // val state = SavedStateHandle(
 | 
				
			||||||
 | 
					        //     mutableMapOf<String, Any?>(
 | 
				
			||||||
 | 
					        //         "username" to "test"
 | 
				
			||||||
 | 
					        //     )
 | 
				
			||||||
 | 
					        // )
 | 
				
			||||||
        val userRepository = UserRepository(UserServiceAdapter())
 | 
					        val userRepository = UserRepository(UserServiceAdapter())
 | 
				
			||||||
        val friendshipRepository = FriendshipRepository(FriendshipServiceAdapter())
 | 
					        val friendshipRepository = FriendshipRepository(FriendshipServiceAdapter())
 | 
				
			||||||
        val storiesRepository = StoriesRepository(StoriesServiceAdapter())
 | 
					        val storiesRepository = StoriesRepository(StoriesServiceAdapter())
 | 
				
			||||||
@ -29,7 +60,7 @@ internal class ProfileFragmentViewModelTest {
 | 
				
			|||||||
        val accountRepository = AccountRepository(accountDataSource)
 | 
					        val accountRepository = AccountRepository(accountDataSource)
 | 
				
			||||||
        val favoriteRepository = FavoriteRepository(FavoriteDataSource(FavoriteDaoAdapter()))
 | 
					        val favoriteRepository = FavoriteRepository(FavoriteDataSource(FavoriteDaoAdapter()))
 | 
				
			||||||
        val viewModel = ProfileFragmentViewModel(
 | 
					        val viewModel = ProfileFragmentViewModel(
 | 
				
			||||||
            state,
 | 
					            SavedStateHandle(),
 | 
				
			||||||
            userRepository,
 | 
					            userRepository,
 | 
				
			||||||
            friendshipRepository,
 | 
					            friendshipRepository,
 | 
				
			||||||
            storiesRepository,
 | 
					            storiesRepository,
 | 
				
			||||||
@ -38,5 +69,11 @@ internal class ProfileFragmentViewModelTest {
 | 
				
			|||||||
            accountRepository,
 | 
					            accountRepository,
 | 
				
			||||||
            favoriteRepository
 | 
					            favoriteRepository
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
 | 
					        assertEquals(false, viewModel.isLoggedIn.getOrAwaitValue())
 | 
				
			||||||
 | 
					        assertNull(viewModel.profile.getOrAwaitValue().data)
 | 
				
			||||||
 | 
					        val user = User()
 | 
				
			||||||
 | 
					        viewModel.currentUser = Resource.success(user)
 | 
				
			||||||
 | 
					        assertEquals(true, viewModel.isLoggedIn.getOrAwaitValue())
 | 
				
			||||||
 | 
					        assertEquals(user, viewModel.profile.getOrAwaitValue().data)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user