diff --git a/domain/BUILD.bazel b/domain/BUILD.bazel old mode 100644 new mode 100755 index d070573ac18..e948096c887 --- a/domain/BUILD.bazel +++ b/domain/BUILD.bazel @@ -307,6 +307,15 @@ domain_test( deps = TEST_DEPS, ) +domain_test( + name = "ItemSelectionInputDoesNotContainAtLeastOneOfRuleClassifierProviderTest", + srcs = [ + "src/test/java/org/oppia/android/domain/classify/rules/textinput/ItemSelectionInputDoesNotContainAtLeastOneOfRuleClassifierProviderTest.kt", + ], + test_class = "org.oppia.android.domain.classify.rules.textinput.ItemSelectionInputDoesNotContainAtLeastOneOfRuleClassifierProviderTest", + deps = TEST_DEPS, +) + domain_test( name = "TextInputEqualsRuleClassifierProviderTest", srcs = [ diff --git a/domain/src/main/java/org/oppia/android/domain/classify/rules/itemselectioninput/ItemSelectionInputDoesNotContainAtLeastOneOfRuleClassifierProvider.kt b/domain/src/main/java/org/oppia/android/domain/classify/rules/itemselectioninput/ItemSelectionInputDoesNotContainAtLeastOneOfRuleClassifierProvider.kt index 0b2ce625d99..d832f865683 100644 --- a/domain/src/main/java/org/oppia/android/domain/classify/rules/itemselectioninput/ItemSelectionInputDoesNotContainAtLeastOneOfRuleClassifierProvider.kt +++ b/domain/src/main/java/org/oppia/android/domain/classify/rules/itemselectioninput/ItemSelectionInputDoesNotContainAtLeastOneOfRuleClassifierProvider.kt @@ -26,7 +26,6 @@ internal class ItemSelectionInputDoesNotContainAtLeastOneOfRuleClassifierProvide ) } - // TODO(#210): Add tests for this classifier. override fun matches(answer: StringList, input: StringList): Boolean { return answer.htmlList.toSet().intersect(input.htmlList).isEmpty() } diff --git a/domain/src/test/java/org/oppia/android/domain/classify/rules/itemselectioninput/ItemSelectionInputDoesNotContainAtLeastOneOfRuleClassifierProviderTest.kt b/domain/src/test/java/org/oppia/android/domain/classify/rules/itemselectioninput/ItemSelectionInputDoesNotContainAtLeastOneOfRuleClassifierProviderTest.kt new file mode 100644 index 00000000000..2b932b3c583 --- /dev/null +++ b/domain/src/test/java/org/oppia/android/domain/classify/rules/itemselectioninput/ItemSelectionInputDoesNotContainAtLeastOneOfRuleClassifierProviderTest.kt @@ -0,0 +1,265 @@ +package org.oppia.android.domain.classify.rules.itemselectioninput + +import android.app.Application +import androidx.test.core.app.ApplicationProvider +import androidx.test.ext.junit.runners.AndroidJUnit4 +import com.google.common.truth.Truth.assertThat +import dagger.BindsInstance +import dagger.Component +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith +import org.oppia.android.domain.classify.InteractionObjectTestBuilder +import org.robolectric.annotation.Config +import org.robolectric.annotation.LooperMode +import java.lang.IllegalStateException +import javax.inject.Inject +import javax.inject.Singleton +import kotlin.reflect.KClass +import kotlin.reflect.full.cast +import kotlin.test.fail + +/** Tests for [ItemSelectionInputDoesNotContainAtLeastOneOfRuleClassifierProvider]. */ +@RunWith(AndroidJUnit4::class) +@LooperMode(LooperMode.Mode.PAUSED) +@Config(manifest = Config.NONE) +class ItemSelectionInputDoesNotContainAtLeastOneOfRuleClassifierProviderTest { + + private val ITEM_SET_12345 = + InteractionObjectTestBuilder.createHtmlStringListInteractionObject( + InteractionObjectTestBuilder + .createHtmlStringList("test1", "test2", "test3", "test4", "test5") + ) + + private val ITEM_SET_1 = + InteractionObjectTestBuilder.createHtmlStringListInteractionObject( + InteractionObjectTestBuilder + .createHtmlStringList("test1") + ) + + private val ITEM_SET_16 = + InteractionObjectTestBuilder.createHtmlStringListInteractionObject( + InteractionObjectTestBuilder + .createHtmlStringList("test1", "test6") + ) + + private val ITEM_SET_12 = + InteractionObjectTestBuilder.createHtmlStringListInteractionObject( + InteractionObjectTestBuilder + .createHtmlStringList("test1", "test2") + ) + + private val ITEM_SET_126 = + InteractionObjectTestBuilder.createHtmlStringListInteractionObject( + InteractionObjectTestBuilder + .createHtmlStringList("test1", "test2", "test6") + ) + + private val ITEM_SET_EMPTY = + InteractionObjectTestBuilder.createHtmlStringListInteractionObject( + InteractionObjectTestBuilder + .createHtmlStringList() + ) + + private val ITEM_SET_6 = + InteractionObjectTestBuilder.createHtmlStringListInteractionObject( + InteractionObjectTestBuilder + .createHtmlStringList("test6") + ) + + private val DIFFERENT_INTERACTION_OBJECT_TYPE = + InteractionObjectTestBuilder.createInt(0) + + @Inject + internal lateinit var itemSelectionInputDesNotContainAtLeastOneOfRuleClassifierProvider: + ItemSelectionInputDoesNotContainAtLeastOneOfRuleClassifierProvider + + private val inputDoesNotContainAtLeastOneOfRuleClassifier by lazy { + itemSelectionInputDesNotContainAtLeastOneOfRuleClassifierProvider.createRuleClassifier() + } + + @Before + fun setUp() { + setUpTestApplicationComponent() + } + + @Test + fun testItemSet_setAnswer_inputIsASubset_answerContainsInput() { + val inputs = mapOf("x" to ITEM_SET_1) + + val matches = inputDoesNotContainAtLeastOneOfRuleClassifier.matches( + answer = ITEM_SET_12345, + inputs = inputs + ) + + assertThat(matches).isFalse() + } + + @Test + fun testItemSet_setAnswer_inputHasOneElementInSet_answerContainsInput() { + val inputs = mapOf("x" to ITEM_SET_16) + + val matches = inputDoesNotContainAtLeastOneOfRuleClassifier.matches( + answer = ITEM_SET_12345, + inputs = inputs + ) + + assertThat(matches).isFalse() + } + + @Test + fun testItemSet_setAnswer_inputHasTwoElementsInSetNoneExtra_answerContainsInput() { + val inputs = mapOf("x" to ITEM_SET_12) + + val matches = inputDoesNotContainAtLeastOneOfRuleClassifier.matches( + answer = ITEM_SET_12345, + inputs = inputs + ) + + assertThat(matches).isFalse() + } + + @Test + fun testItemSet_setAnswer_inputHasTwoElementsInSetOneExtra_answerContainsInput() { + val inputs = mapOf("x" to ITEM_SET_126) + + val matches = inputDoesNotContainAtLeastOneOfRuleClassifier.matches( + answer = ITEM_SET_12345, + inputs = inputs + ) + + assertThat(matches).isFalse() + } + + @Test + fun testItemSet_setAnswer_inputIsEmptySet_answerDoesNotContainInput() { + val inputs = mapOf("x" to ITEM_SET_EMPTY) + + val matches = inputDoesNotContainAtLeastOneOfRuleClassifier.matches( + answer = ITEM_SET_12345, + inputs = inputs + ) + + assertThat(matches).isTrue() + } + + @Test + fun testItemSet_setAnswer_inputIsExclusiveOfSet_answerDoesNotContainInput() { + val inputs = mapOf("x" to ITEM_SET_6) + + val matches = inputDoesNotContainAtLeastOneOfRuleClassifier.matches( + answer = ITEM_SET_12345, + inputs = inputs + ) + + assertThat(matches).isTrue() + } + + @Test + fun testItemSet_setAnswerIsEmpty_inputIsNonEmpty_answerDoesNotContainInput() { + val inputs = mapOf("x" to ITEM_SET_12345) + + val matches = inputDoesNotContainAtLeastOneOfRuleClassifier.matches( + answer = ITEM_SET_EMPTY, + inputs = inputs + ) + + assertThat(matches).isTrue() + } + + @Test + fun testItemSet_setAnswer_inputIsASuperset_answerContainsInput() { + val inputs = mapOf("x" to ITEM_SET_12345) + + val matches = inputDoesNotContainAtLeastOneOfRuleClassifier.matches( + answer = ITEM_SET_12, + inputs = inputs + ) + + assertThat(matches).isFalse() + } + + @Test + fun testItemSet_inputIsMissing_throwsException() { + val inputs = mapOf("y" to ITEM_SET_1) + + val exception = assertThrows(IllegalStateException::class) { + inputDoesNotContainAtLeastOneOfRuleClassifier.matches( + answer = ITEM_SET_12345, + inputs = inputs + ) + } + + assertThat(exception) + .hasMessageThat() + .contains("Expected classifier inputs to contain parameter with name 'x'") + } + + @Test + fun testItemSet_inputHasTheWrongType_throwsException() { + val inputs = mapOf("x" to DIFFERENT_INTERACTION_OBJECT_TYPE) + + val exception = assertThrows(IllegalStateException::class) { + inputDoesNotContainAtLeastOneOfRuleClassifier.matches( + answer = ITEM_SET_12345, + inputs = inputs + ) + } + + assertThat(exception) + .hasMessageThat() + .contains("Expected input value to be of type SET_OF_HTML_STRING") + } + + @Test + fun testItemSet_answerHasTheWrongType_throwsException() { + val inputs = mapOf("x" to ITEM_SET_12345) + + val exception = assertThrows(IllegalStateException::class) { + inputDoesNotContainAtLeastOneOfRuleClassifier.matches( + answer = DIFFERENT_INTERACTION_OBJECT_TYPE, + inputs = inputs + ) + } + + assertThat(exception) + .hasMessageThat() + .contains("Expected answer to be of type SET_OF_HTML_STRING") + } + + private fun setUpTestApplicationComponent() { + DaggerItemSelectionInputDoesNotContainAtLeastOneOfRuleClassifierProviderTest_TestApplicationComponent // ktlint-disable max-line-length + .builder() + .setApplication(ApplicationProvider.getApplicationContext()) + .build() + .inject(this) + } + + // TODO(#89): Move to a common test library. + private fun assertThrows(type: KClass, operation: () -> Unit): T { + try { + operation() + fail("Expected to encounter exception of $type") + } catch (t: Throwable) { + if (type.isInstance(t)) { + return type.cast(t) + } + // Unexpected exception; throw it. + throw t + } + } + + @Singleton + @Component(modules = []) + interface TestApplicationComponent { + @Component.Builder + interface Builder { + @BindsInstance + fun setApplication(application: Application): Builder + + fun build(): TestApplicationComponent + } + + fun inject(test: ItemSelectionInputDoesNotContainAtLeastOneOfRuleClassifierProviderTest) + } +}