diff --git a/app/src/main/java/com/afollestad/nocknock/ui/addsite/AddSiteViewModel.kt b/app/src/main/java/com/afollestad/nocknock/ui/addsite/AddSiteViewModel.kt index ebcc4ba..4f51b73 100644 --- a/app/src/main/java/com/afollestad/nocknock/ui/addsite/AddSiteViewModel.kt +++ b/app/src/main/java/com/afollestad/nocknock/ui/addsite/AddSiteViewModel.kt @@ -16,6 +16,8 @@ package com.afollestad.nocknock.ui.addsite import androidx.annotation.CheckResult +import androidx.annotation.VisibleForTesting +import androidx.annotation.VisibleForTesting.PRIVATE import androidx.lifecycle.LifecycleObserver import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData @@ -74,10 +76,7 @@ class AddSiteViewModel( @CheckResult fun onUrlWarningVisibility(): LiveData { return url.map { val parsed = HttpUrl.parse(it) - return@map it.isNotEmpty() && - parsed != null && - parsed.scheme() != "http" && - parsed.scheme() != "https" + return@map it.isNotEmpty() && parsed == null } } @@ -85,11 +84,10 @@ class AddSiteViewModel( @CheckResult fun onValidationModeDescription(): LiveData { return validationMode.map { - when (it) { + when (it!!) { STATUS_CODE -> R.string.validation_mode_status_desc TERM_SEARCH -> R.string.validation_mode_term_desc JAVASCRIPT -> R.string.validation_mode_javascript_desc - else -> throw IllegalStateException("Unknown validation mode: $it") } } } @@ -127,13 +125,15 @@ class AddSiteViewModel( } // Utilities - private fun getCheckIntervalMs(): Long { + @VisibleForTesting(otherwise = PRIVATE) + fun getCheckIntervalMs(): Long { val value = checkIntervalValue.value ?: return 0 val unit = checkIntervalUnit.value ?: return 0 return value * unit } - private fun getValidationArgs(): String? { + @VisibleForTesting(otherwise = PRIVATE) + fun getValidationArgs(): String? { return when (validationMode.value) { TERM_SEARCH -> validationSearchTerm.value JAVASCRIPT -> validationScript.value @@ -184,13 +184,13 @@ class AddSiteViewModel( } // Validate arguments - if (validationMode == TERM_SEARCH && + if (validationMode.value == TERM_SEARCH && validationSearchTerm.value.isNullOrEmpty() ) { errorCount++ validationSearchTermError.value = R.string.please_enter_search_term validationScriptError.value = null - } else if (validationMode == JAVASCRIPT && + } else if (validationMode.value == JAVASCRIPT && validationScript.value.isNullOrEmpty() ) { errorCount++ diff --git a/app/src/test/java/com/afollestad/nocknock/LiveDataTestUtil.kt b/app/src/test/java/com/afollestad/nocknock/LiveDataTestUtil.kt index e175d5d..0556668 100644 --- a/app/src/test/java/com/afollestad/nocknock/LiveDataTestUtil.kt +++ b/app/src/test/java/com/afollestad/nocknock/LiveDataTestUtil.kt @@ -25,7 +25,9 @@ import com.google.common.truth.Truth.assertWithMessage class TestLiveData(data: LiveData) { private val receivedValues = mutableListOf() - private val observer = Observer { receivedValues.add(it) } + private val observer = Observer { emission -> + emission?.let { receivedValues.add(it) } + } init { data.observeForever(observer) diff --git a/app/src/test/java/com/afollestad/nocknock/ui/addsite/AddSiteViewModelTest.kt b/app/src/test/java/com/afollestad/nocknock/ui/addsite/AddSiteViewModelTest.kt index d8cbe81..08af8fd 100644 --- a/app/src/test/java/com/afollestad/nocknock/ui/addsite/AddSiteViewModelTest.kt +++ b/app/src/test/java/com/afollestad/nocknock/ui/addsite/AddSiteViewModelTest.kt @@ -15,287 +15,411 @@ */ package com.afollestad.nocknock.ui.addsite -//import com.afollestad.nocknock.R.string -//import com.afollestad.nocknock.data.model.Site -//import com.afollestad.nocknock.data.model.SiteSettings -//import com.afollestad.nocknock.data.model.ValidationMode.JAVASCRIPT -//import com.afollestad.nocknock.data.model.ValidationMode.STATUS_CODE -//import com.afollestad.nocknock.data.model.ValidationMode.TERM_SEARCH -//import com.afollestad.nocknock.engine.validation.ValidationManager -//import com.afollestad.nocknock.mockDatabase -//import com.afollestad.nocknock.ui.addsite.AddSiteView -//import com.afollestad.nocknock.ui.addsite.InputErrors -//import com.afollestad.nocknock.ui.addsite.RealAddSitePresenter -//import com.afollestad.nocknock.utilities.ext.ScopeReceiver -//import com.google.common.truth.Truth.assertThat -//import com.nhaarman.mockitokotlin2.any -//import com.nhaarman.mockitokotlin2.argumentCaptor -//import com.nhaarman.mockitokotlin2.doAnswer -//import com.nhaarman.mockitokotlin2.mock -//import com.nhaarman.mockitokotlin2.never -//import com.nhaarman.mockitokotlin2.times -//import com.nhaarman.mockitokotlin2.verify -//import com.nhaarman.mockitokotlin2.verifyNoMoreInteractions -//import com.nhaarman.mockitokotlin2.whenever -//import kotlinx.coroutines.runBlocking -//import org.junit.After -//import org.junit.Before -//import org.junit.Test -// -//class AddSiteViewModelTest { -// -// private val database = mockDatabase() -// private val checkStatusManager = mock() -// private val view = mock() -// -// private val presenter = RealAddSitePresenter( -// database, -// checkStatusManager -// ) -// -// @Before fun setup() { -// doAnswer { -// val exec = it.getArgument(1) -// runBlocking { exec() } -// Unit -// }.whenever(view) -// .scopeWhileAttached(any(), any()) -// -// presenter.takeView(view) -// } -// -// @After fun destroy() { -// presenter.dropView() -// } -// -// @Test fun onUrlInputFocusChange_focused() { -// presenter.onUrlInputFocusChange(true, "hello") -// verifyNoMoreInteractions(view) -// } -// -// @Test fun onUrlInputFocusChange_empty() { -// presenter.onUrlInputFocusChange(false, "") -// verifyNoMoreInteractions(view) -// } -// -// @Test fun onUrlInputFocusChange_notHttpHttps() { -// presenter.onUrlInputFocusChange(false, "ftp://hello.com") -// verify(view).showOrHideUrlSchemeWarning(true) -// } -// -// @Test fun onUrlInputFocusChange_isHttpOrHttps() { -// presenter.onUrlInputFocusChange(false, "http://hello.com") -// presenter.onUrlInputFocusChange(false, "https://hello.com") -// verify(view, times(2)).showOrHideUrlSchemeWarning(false) -// } -// -// @Test fun onValidationModeSelected_statusCode() { -// presenter.onValidationModeSelected(0) -// verify(view).showOrHideValidationSearchTerm(false) -// verify(view).showOrHideScriptInput(false) -// verify(view).setValidationModeDescription( -// string.validation_mode_status_desc -// ) -// } -// -// @Test fun onValidationModeSelected_termSearch() { -// presenter.onValidationModeSelected(1) -// verify(view).showOrHideValidationSearchTerm(true) -// verify(view).showOrHideScriptInput(false) -// verify(view).setValidationModeDescription( -// string.validation_mode_term_desc -// ) -// } -// -// @Test fun onValidationModeSelected_javaScript() { -// presenter.onValidationModeSelected(2) -// verify(view).showOrHideValidationSearchTerm(false) -// verify(view).showOrHideScriptInput(true) -// verify(view).setValidationModeDescription( -// string.validation_mode_javascript_desc -// ) -// } -// -// @Test(expected = IllegalStateException::class) -// fun onValidationModeSelected_other() { -// presenter.onValidationModeSelected(3) -// } -// -// @Test fun commit_nameError() { -// presenter.commit( -// "", -// "https://test.com", -// 1, -// STATUS_CODE, -// null, -// 60000 -// ) -// -// val inputErrorsCaptor = argumentCaptor() -// verify(view).setInputErrors(inputErrorsCaptor.capture()) -// verify(checkStatusManager, never()) -// .scheduleCheck(any(), any(), any(), any()) -// -// val errors = inputErrorsCaptor.firstValue -// assertThat(errors.name).isEqualTo(string.please_enter_name) -// } -// -// @Test fun commit_urlEmptyError() { -// presenter.commit( -// "Testing", -// "", -// 1, -// STATUS_CODE, -// null, -// 60000 -// ) -// -// val inputErrorsCaptor = argumentCaptor() -// verify(view).setInputErrors(inputErrorsCaptor.capture()) -// verify(checkStatusManager, never()) -// .scheduleCheck(any(), any(), any(), any()) -// -// val errors = inputErrorsCaptor.firstValue -// assertThat(errors.url).isEqualTo(string.please_enter_url) -// } -// -// @Test fun commit_urlFormatError() { -// presenter.commit( -// "Testing", -// "ftp://hello.com", -// 1, -// STATUS_CODE, -// null, -// 60000 -// ) -// -// val inputErrorsCaptor = argumentCaptor() -// verify(view).setInputErrors(inputErrorsCaptor.capture()) -// verify(checkStatusManager, never()) -// .scheduleCheck(any(), any(), any(), any()) -// -// val errors = inputErrorsCaptor.firstValue -// assertThat(errors.url).isEqualTo(string.please_enter_valid_url) -// } -// -// @Test fun commit_checkIntervalError() { -// presenter.commit( -// "Testing", -// "https://hello.com", -// -1, -// STATUS_CODE, -// null, -// 60000 -// ) -// -// val inputErrorsCaptor = argumentCaptor() -// verify(view).setInputErrors(inputErrorsCaptor.capture()) -// verify(checkStatusManager, never()) -// .scheduleCheck(any(), any(), any(), any()) -// -// val errors = inputErrorsCaptor.firstValue -// assertThat(errors.checkInterval).isEqualTo( -// string.please_enter_check_interval -// ) -// } -// -// @Test fun commit_termSearchError() { -// presenter.commit( -// "Testing", -// "https://hello.com", -// 1, -// TERM_SEARCH, -// null, -// 60000 -// ) -// -// val inputErrorsCaptor = argumentCaptor() -// verify(view).setInputErrors(inputErrorsCaptor.capture()) -// verify(checkStatusManager, never()) -// .scheduleCheck(any(), any(), any(), any()) -// -// val errors = inputErrorsCaptor.firstValue -// assertThat(errors.termSearch).isEqualTo( -// string.please_enter_search_term -// ) -// } -// -// @Test fun commit_networkTimeout_error() { -// presenter.commit( -// "Testing", -// "https://hello.com", -// 1, -// STATUS_CODE, -// null, -// 0 -// ) -// -// val inputErrorsCaptor = argumentCaptor() -// verify(view).setInputErrors(inputErrorsCaptor.capture()) -// verify(checkStatusManager, never()) -// .scheduleCheck(any(), any(), any(), any()) -// -// val errors = inputErrorsCaptor.firstValue -// assertThat(errors.networkTimeout).isEqualTo( -// string.please_enter_networkTimeout -// ) -// } -// -// @Test fun commit_javaScript_error() { -// presenter.commit( -// "Testing", -// "https://hello.com", -// 1, -// JAVASCRIPT, -// null, -// 60000 -// ) -// -// val inputErrorsCaptor = argumentCaptor() -// verify(view).setInputErrors(inputErrorsCaptor.capture()) -// verify(checkStatusManager, never()) -// .scheduleCheck(any(), any(), any(), any()) -// -// val errors = inputErrorsCaptor.firstValue -// assertThat(errors.javaScript).isEqualTo( -// string.please_enter_javaScript -// ) -// } -// -// @Test fun commit_success() = runBlocking { -// presenter.commit( -// "Testing", -// "https://hello.com", -// 1, -// STATUS_CODE, -// null, -// 60000 -// ) -// -// val siteCaptor = argumentCaptor() -// val settingsCaptor = argumentCaptor() -// -// verify(view).setLoading() -// verify(database.siteDao()).insert(siteCaptor.capture()) -// verify(database.siteSettingsDao()).insert(settingsCaptor.capture()) -// verify(database.validationResultsDao(), never()).insert(any()) -// -// val settings = settingsCaptor.firstValue -// val model = siteCaptor.firstValue.copy( -// id = 1, // fill it in because our insert captor doesn't catch this -// settings = settings, -// lastResult = null -// ) -// -// verify(view, never()).setInputErrors(any()) -// verify(checkStatusManager).scheduleCheck( -// site = model, -// rightNow = true, -// cancelPrevious = true, -// fromFinishingJob = false -// ) -// -// verify(view).setDoneLoading() -// verify(view).onSiteAdded() -// } -//} +import androidx.arch.core.executor.testing.InstantTaskExecutorRule +import com.afollestad.nocknock.R +import com.afollestad.nocknock.data.model.Site +import com.afollestad.nocknock.data.model.SiteSettings +import com.afollestad.nocknock.data.model.ValidationMode.JAVASCRIPT +import com.afollestad.nocknock.data.model.ValidationMode.STATUS_CODE +import com.afollestad.nocknock.data.model.ValidationMode.TERM_SEARCH +import com.afollestad.nocknock.engine.validation.ValidationManager +import com.afollestad.nocknock.mockDatabase +import com.afollestad.nocknock.test +import com.google.common.truth.Truth.assertThat +import com.nhaarman.mockitokotlin2.any +import com.nhaarman.mockitokotlin2.argumentCaptor +import com.nhaarman.mockitokotlin2.mock +import com.nhaarman.mockitokotlin2.never +import com.nhaarman.mockitokotlin2.verify +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.runBlocking +import org.junit.After +import org.junit.Rule +import org.junit.Test + +/** @author Aidan Follestad (@afollestad) */ +@ExperimentalCoroutinesApi +class AddSiteViewModelTest { + + private val database = mockDatabase() + private val validationManager = mock() + + @Rule @JvmField val rule = InstantTaskExecutorRule() + + private val viewModel = AddSiteViewModel( + database, + validationManager, + Dispatchers.Unconfined, + Dispatchers.Unconfined + ) + + @After fun tearDown() = viewModel.destroy() + + @Test fun onUrlWarningVisibility() { + val urlWarningVisibility = viewModel.onUrlWarningVisibility() + .test() + + viewModel.url.value = "" + urlWarningVisibility.assertValues(false) + + viewModel.url.value = "helloworld" + urlWarningVisibility.assertValues(true) + + viewModel.url.value = "http://helloworld.com" + urlWarningVisibility.assertValues(false) + + viewModel.url.value = "ftp://helloworld.com" + urlWarningVisibility.assertValues(true) + } + + @Test fun onValidationModeDescription() { + val description = viewModel.onValidationModeDescription() + .test() + + viewModel.validationMode.value = STATUS_CODE + description.assertValues(R.string.validation_mode_status_desc) + + viewModel.validationMode.value = TERM_SEARCH + description.assertValues(R.string.validation_mode_term_desc) + + viewModel.validationMode.value = JAVASCRIPT + description.assertValues(R.string.validation_mode_javascript_desc) + } + + @Test fun onValidationSearchTermVisibility() { + val visibility = viewModel.onValidationSearchTermVisibility() + .test() + + viewModel.validationMode.value = STATUS_CODE + visibility.assertValues(false) + + viewModel.validationMode.value = TERM_SEARCH + visibility.assertValues(true) + + viewModel.validationMode.value = JAVASCRIPT + visibility.assertValues(false) + } + + @Test fun onValidationScriptVisibility() { + val visibility = viewModel.onValidationScriptVisibility() + .test() + + viewModel.validationMode.value = STATUS_CODE + visibility.assertValues(false) + + viewModel.validationMode.value = TERM_SEARCH + visibility.assertValues(false) + + viewModel.validationMode.value = JAVASCRIPT + visibility.assertValues(true) + } + + @Test fun getCheckIntervalMs() { + viewModel.checkIntervalValue.value = 3 + viewModel.checkIntervalUnit.value = 200 + assertThat(viewModel.getCheckIntervalMs()).isEqualTo(600L) + } + + @Test fun getValidationArgs() { + viewModel.validationSearchTerm.value = "One" + viewModel.validationScript.value = "Two" + + viewModel.validationMode.value = STATUS_CODE + assertThat(viewModel.getValidationArgs()).isNull() + + viewModel.validationMode.value = TERM_SEARCH + assertThat(viewModel.getValidationArgs()).isEqualTo("One") + + viewModel.validationMode.value = JAVASCRIPT + assertThat(viewModel.getValidationArgs()).isEqualTo("Two") + } + + @Test fun commit_nameError() { + val onNameError = viewModel.onNameError() + .test() + val onUrlError = viewModel.onUrlError() + .test() + val onTimeoutError = viewModel.onTimeoutError() + .test() + val onCheckIntervalError = viewModel.onCheckIntervalError() + .test() + val onSearchTermError = viewModel.onValidationSearchTermError() + .test() + val onScriptError = viewModel.onValidationScriptError() + .test() + + fillInModel().apply { + name.value = "" + } + val onDone = mock<() -> Unit>() + viewModel.commit(onDone) + + verify(validationManager, never()) + .scheduleCheck(any(), any(), any(), any()) + onNameError.assertValues(R.string.please_enter_name) + onUrlError.assertNoValues() + onTimeoutError.assertNoValues() + onCheckIntervalError.assertNoValues() + onSearchTermError.assertNoValues() + onScriptError.assertNoValues() + + verify(onDone, never()).invoke() + } + + @Test fun commit_urlEmptyError() { + val onNameError = viewModel.onNameError() + .test() + val onUrlError = viewModel.onUrlError() + .test() + val onTimeoutError = viewModel.onTimeoutError() + .test() + val onCheckIntervalError = viewModel.onCheckIntervalError() + .test() + val onSearchTermError = viewModel.onValidationSearchTermError() + .test() + val onScriptError = viewModel.onValidationScriptError() + .test() + + fillInModel().apply { + url.value = "" + } + val onDone = mock<() -> Unit>() + viewModel.commit(onDone) + + verify(validationManager, never()) + .scheduleCheck(any(), any(), any(), any()) + onNameError.assertNoValues() + onUrlError.assertValues(R.string.please_enter_url) + onTimeoutError.assertNoValues() + onCheckIntervalError.assertNoValues() + onSearchTermError.assertNoValues() + onScriptError.assertNoValues() + + verify(onDone, never()).invoke() + } + + @Test fun commit_urlFormatError() { + val onNameError = viewModel.onNameError() + .test() + val onUrlError = viewModel.onUrlError() + .test() + val onTimeoutError = viewModel.onTimeoutError() + .test() + val onCheckIntervalError = viewModel.onCheckIntervalError() + .test() + val onSearchTermError = viewModel.onValidationSearchTermError() + .test() + val onScriptError = viewModel.onValidationScriptError() + .test() + + fillInModel().apply { + url.value = "ftp://www.idk.com" + } + val onDone = mock<() -> Unit>() + viewModel.commit(onDone) + + verify(validationManager, never()) + .scheduleCheck(any(), any(), any(), any()) + onNameError.assertNoValues() + onUrlError.assertValues(R.string.please_enter_valid_url) + onTimeoutError.assertNoValues() + onCheckIntervalError.assertNoValues() + onSearchTermError.assertNoValues() + onScriptError.assertNoValues() + + verify(onDone, never()).invoke() + } + + @Test fun commit_networkTimeout_error() { + val onNameError = viewModel.onNameError() + .test() + val onUrlError = viewModel.onUrlError() + .test() + val onTimeoutError = viewModel.onTimeoutError() + .test() + val onCheckIntervalError = viewModel.onCheckIntervalError() + .test() + val onSearchTermError = viewModel.onValidationSearchTermError() + .test() + val onScriptError = viewModel.onValidationScriptError() + .test() + + fillInModel().apply { + timeout.value = 0 + } + val onDone = mock<() -> Unit>() + viewModel.commit(onDone) + + verify(validationManager, never()) + .scheduleCheck(any(), any(), any(), any()) + onNameError.assertNoValues() + onUrlError.assertNoValues() + onTimeoutError.assertValues(R.string.please_enter_networkTimeout) + onCheckIntervalError.assertNoValues() + onSearchTermError.assertNoValues() + onScriptError.assertNoValues() + + verify(onDone, never()).invoke() + } + + @Test fun commit_checkIntervalError() { + val onNameError = viewModel.onNameError() + .test() + val onUrlError = viewModel.onUrlError() + .test() + val onTimeoutError = viewModel.onTimeoutError() + .test() + val onCheckIntervalError = viewModel.onCheckIntervalError() + .test() + val onSearchTermError = viewModel.onValidationSearchTermError() + .test() + val onScriptError = viewModel.onValidationScriptError() + .test() + + fillInModel().apply { + checkIntervalValue.value = 0 + } + val onDone = mock<() -> Unit>() + viewModel.commit(onDone) + + verify(validationManager, never()) + .scheduleCheck(any(), any(), any(), any()) + onNameError.assertNoValues() + onUrlError.assertNoValues() + onTimeoutError.assertNoValues() + onCheckIntervalError.assertValues(R.string.please_enter_check_interval) + onSearchTermError.assertNoValues() + onScriptError.assertNoValues() + + verify(onDone, never()).invoke() + } + + @Test fun commit_termSearchError() { + val onNameError = viewModel.onNameError() + .test() + val onUrlError = viewModel.onUrlError() + .test() + val onTimeoutError = viewModel.onTimeoutError() + .test() + val onCheckIntervalError = viewModel.onCheckIntervalError() + .test() + val onSearchTermError = viewModel.onValidationSearchTermError() + .test() + val onScriptError = viewModel.onValidationScriptError() + .test() + + fillInModel().apply { + validationMode.value = TERM_SEARCH + validationSearchTerm.value = "" + } + val onDone = mock<() -> Unit>() + viewModel.commit(onDone) + + verify(validationManager, never()) + .scheduleCheck(any(), any(), any(), any()) + onNameError.assertNoValues() + onUrlError.assertNoValues() + onTimeoutError.assertNoValues() + onCheckIntervalError.assertNoValues() + onSearchTermError.assertValues(R.string.please_enter_search_term) + onScriptError.assertNoValues() + + verify(onDone, never()).invoke() + } + + @Test fun commit_javaScript_error() { + val onNameError = viewModel.onNameError() + .test() + val onUrlError = viewModel.onUrlError() + .test() + val onTimeoutError = viewModel.onTimeoutError() + .test() + val onCheckIntervalError = viewModel.onCheckIntervalError() + .test() + val onSearchTermError = viewModel.onValidationSearchTermError() + .test() + val onScriptError = viewModel.onValidationScriptError() + .test() + + fillInModel().apply { + validationMode.value = JAVASCRIPT + validationScript.value = "" + } + val onDone = mock<() -> Unit>() + viewModel.commit(onDone) + + verify(validationManager, never()) + .scheduleCheck(any(), any(), any(), any()) + onNameError.assertNoValues() + onUrlError.assertNoValues() + onTimeoutError.assertNoValues() + onCheckIntervalError.assertNoValues() + onSearchTermError.assertNoValues() + onScriptError.assertValues(R.string.please_enter_javaScript) + + verify(onDone, never()).invoke() + } + + @Test fun commit_success() = runBlocking { + val isLoading = viewModel.onIsLoading() + .test() + val onNameError = viewModel.onNameError() + .test() + val onUrlError = viewModel.onUrlError() + .test() + val onTimeoutError = viewModel.onTimeoutError() + .test() + val onSearchTermError = viewModel.onValidationSearchTermError() + .test() + val onScriptError = viewModel.onValidationScriptError() + .test() + val onCheckIntervalError = viewModel.onCheckIntervalError() + .test() + + fillInModel() + val onDone = mock<() -> Unit>() + viewModel.commit(onDone) + + val siteCaptor = argumentCaptor() + val settingsCaptor = argumentCaptor() + + isLoading.assertValues(true, false) + verify(database.siteDao()).insert(siteCaptor.capture()) + verify(database.siteSettingsDao()).insert(settingsCaptor.capture()) + verify(database.validationResultsDao(), never()).insert(any()) + + val settings = settingsCaptor.firstValue + val model = siteCaptor.firstValue.copy( + id = 1, // fill it in because our insert captor doesn't catch this + settings = settings, + lastResult = null + ) + + verify(validationManager).scheduleCheck( + site = model, + rightNow = true, + cancelPrevious = true, + fromFinishingJob = false + ) + onNameError.assertNoValues() + onUrlError.assertNoValues() + onTimeoutError.assertNoValues() + onCheckIntervalError.assertNoValues() + onSearchTermError.assertNoValues() + onScriptError.assertNoValues() + + verify(onDone).invoke() + } + + private fun fillInModel() = viewModel.apply { + name.value = "Welcome to Wakanda" + url.value = "https://www.wakanda.gov" + timeout.value = 10000 + validationMode.value = TERM_SEARCH + validationSearchTerm.value = "T'Challa" + validationScript.value = null + checkIntervalValue.value = 60 + checkIntervalUnit.value = 1000 + } +} diff --git a/app/src/test/java/com/afollestad/nocknock/ui/main/MainViewModelTest.kt b/app/src/test/java/com/afollestad/nocknock/ui/main/MainViewModelTest.kt index 70e732f..fba42db 100644 --- a/app/src/test/java/com/afollestad/nocknock/ui/main/MainViewModelTest.kt +++ b/app/src/test/java/com/afollestad/nocknock/ui/main/MainViewModelTest.kt @@ -27,12 +27,14 @@ import com.afollestad.nocknock.test import com.nhaarman.mockitokotlin2.mock import com.nhaarman.mockitokotlin2.verify import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.runBlocking import org.junit.After import org.junit.Rule import org.junit.Test /** @author Aidan Follestad (@afollestad) */ +@ExperimentalCoroutinesApi class MainViewModelTest { private val database = mockDatabase()