diff --git a/scripts/assets/test_file_exemptions.textproto b/scripts/assets/test_file_exemptions.textproto index 8529317da0b..edcfea18f81 100644 --- a/scripts/assets/test_file_exemptions.textproto +++ b/scripts/assets/test_file_exemptions.textproto @@ -4098,10 +4098,6 @@ test_file_exemption { exempted_file_path: "testing/src/main/java/org/oppia/android/testing/logging/SyncStatusTestModule.kt" override_min_coverage_percent_required: 0 } -test_file_exemption { - exempted_file_path: "testing/src/main/java/org/oppia/android/testing/math/ComparableOperationSubject.kt" - test_file_not_required: true -} test_file_exemption { exempted_file_path: "testing/src/main/java/org/oppia/android/testing/math/MathParsingErrorSubject.kt" test_file_not_required: true diff --git a/testing/src/main/java/org/oppia/android/testing/math/ComparableOperationSubject.kt b/testing/src/main/java/org/oppia/android/testing/math/ComparableOperationSubject.kt index 06dd8bae7ba..cddce924cdb 100644 --- a/testing/src/main/java/org/oppia/android/testing/math/ComparableOperationSubject.kt +++ b/testing/src/main/java/org/oppia/android/testing/math/ComparableOperationSubject.kt @@ -12,8 +12,6 @@ import org.oppia.android.app.model.ComparableOperation.ComparisonTypeCase import org.oppia.android.app.model.Real import org.oppia.android.testing.math.RealSubject.Companion.assertThat -// TODO(#4098): Add tests for this class. - /** * Truth subject for verifying properties of [ComparableOperation]s. * diff --git a/testing/src/test/java/org/oppia/android/testing/math/BUILD.bazel b/testing/src/test/java/org/oppia/android/testing/math/BUILD.bazel index 354acf48077..1e8c7ab230a 100644 --- a/testing/src/test/java/org/oppia/android/testing/math/BUILD.bazel +++ b/testing/src/test/java/org/oppia/android/testing/math/BUILD.bazel @@ -67,3 +67,18 @@ oppia_android_test( "//third_party:robolectric_android-all", ], ) + +oppia_android_test( + name = "ComparableOperationSubjectTest", + srcs = ["ComparableOperationSubjectTest.kt"], + custom_package = "org.oppia.android.testing.math", + test_class = "org.oppia.android.testing.math.ComparableOperationSubjectTest", + test_manifest = "//testing:test_manifest", + deps = [ + "//testing/src/main/java/org/oppia/android/testing/math:comparable_operation_subject", + "//testing/src/main/java/org/oppia/android/testing/robolectric:test_module", + "//third_party:com_google_truth_truth", + "//third_party:junit_junit", + "//third_party:robolectric_android-all", + ], +) diff --git a/testing/src/test/java/org/oppia/android/testing/math/ComparableOperationSubjectTest.kt b/testing/src/test/java/org/oppia/android/testing/math/ComparableOperationSubjectTest.kt new file mode 100644 index 00000000000..0304c8c1ac0 --- /dev/null +++ b/testing/src/test/java/org/oppia/android/testing/math/ComparableOperationSubjectTest.kt @@ -0,0 +1,428 @@ +package org.oppia.android.testing.math + +import org.junit.Assert.assertThrows +import org.junit.Test +import org.junit.runner.RunWith +import org.junit.runners.JUnit4 +import org.oppia.android.app.model.ComparableOperation +import org.oppia.android.app.model.Real + +/** Tests for [ComparableOperationSubject]. */ +@RunWith(JUnit4::class) +class ComparableOperationSubjectTest { + + private fun createConstantOperation(value: Int): ComparableOperation { + return ComparableOperation.newBuilder() + .setConstantTerm(Real.newBuilder().setInteger(value)) + .build() + } + + private fun createVariableOperation(name: String): ComparableOperation { + return ComparableOperation.newBuilder() + .setVariableTerm(name) + .build() + } + + private fun createCommutativeAccumulation( + type: ComparableOperation.CommutativeAccumulation.AccumulationType, + vararg operations: ComparableOperation + ): ComparableOperation { + val accumulation = ComparableOperation.CommutativeAccumulation.newBuilder() + .setAccumulationType(type) + operations.forEach { accumulation.addCombinedOperations(it) } + return ComparableOperation.newBuilder() + .setCommutativeAccumulation(accumulation) + .build() + } + + @Test + fun testComparableOperationSubject_hasStructureThatMatches() { + val operation = createConstantOperation(42) + + ComparableOperationSubject.assertThat(operation).hasStructureThatMatches { + constantTerm { + withValueThat().isIntegerThat().isEqualTo(42) + } + } + } + + @Test + fun testComparableOperationSubject_failsWithInvalidStructure() { + val operation = createConstantOperation(42) + assertThrows(AssertionError::class.java) { + ComparableOperationSubject.assertThat(operation).hasStructureThatMatches { + variableTerm { + withNameThat().isEqualTo("x") + } + } + } + } + + @Test + fun testComparableOperationSubject_hasNegatedProperty_matchesFalse() { + val operation = createConstantOperation(42) + + ComparableOperationSubject.assertThat(operation).hasStructureThatMatches { + hasNegatedPropertyThat().isFalse() + } + } + + @Test + fun testComparableOperationSubject_hasNegatedPropertyThat_matchesTrue() { + val operation = ComparableOperation.newBuilder() + .setConstantTerm(Real.newBuilder().setInteger(42)) + .setIsNegated(true) + .build() + + ComparableOperationSubject.assertThat(operation).hasStructureThatMatches { + hasNegatedPropertyThat().isTrue() + } + } + + @Test + fun testComparableOperationSubject_hasInvertedProperty_matchesFalse() { + val operation = createConstantOperation(42) + + ComparableOperationSubject.assertThat(operation).hasStructureThatMatches { + hasInvertedPropertyThat().isFalse() + } + } + + @Test + fun testComparableOperationSubject_hasInvertedProperty() { + val operation = ComparableOperation.newBuilder() + .setConstantTerm(Real.newBuilder().setInteger(42)) + .setIsInverted(true) + .build() + + ComparableOperationSubject.assertThat(operation).hasStructureThatMatches { + hasInvertedPropertyThat().isTrue() + } + } + + @Test + fun testComparableOperationSubject_commutativeAccumulation_withValidSummation() { + val operation = createCommutativeAccumulation( + ComparableOperation.CommutativeAccumulation.AccumulationType.SUMMATION, + createConstantOperation(1), + createConstantOperation(2) + ) + + ComparableOperationSubject.assertThat(operation).hasStructureThatMatches { + commutativeAccumulationWithType( + ComparableOperation.CommutativeAccumulation + .AccumulationType.SUMMATION + ) { + hasOperandCountThat().isEqualTo(2) + index(0) { + constantTerm { + withValueThat().isIntegerThat().isEqualTo(1) + } + } + index(1) { + constantTerm { + withValueThat().isIntegerThat().isEqualTo(2) + } + } + } + } + } + + @Test + fun testComparableOperationSubject_commutativeAccumulation_withEmptyAccumulation() { + val operation = createCommutativeAccumulation( + ComparableOperation.CommutativeAccumulation.AccumulationType.SUMMATION + ) + + ComparableOperationSubject.assertThat(operation).hasStructureThatMatches { + commutativeAccumulationWithType( + ComparableOperation.CommutativeAccumulation + .AccumulationType.SUMMATION + ) { + hasOperandCountThat().isEqualTo(0) + } + } + } + + @Test + fun testComparableOperationSubject_commutativeAccumulationFailsWithInvalidType() { + val operation = createConstantOperation(42) + assertThrows(AssertionError::class.java) { + ComparableOperationSubject.assertThat(operation).hasStructureThatMatches { + commutativeAccumulationWithType( + ComparableOperation.CommutativeAccumulation + .AccumulationType.SUMMATION + ) { + hasOperandCountThat().isEqualTo(0) + } + } + } + } + + @Test + fun testComparableOperationSubject_commutativeAccumulation_failsWithInvalidIndex() { + val operation = createCommutativeAccumulation( + ComparableOperation.CommutativeAccumulation.AccumulationType.SUMMATION, + createConstantOperation(1) + ) + assertThrows(IndexOutOfBoundsException::class.java) { + ComparableOperationSubject.assertThat(operation).hasStructureThatMatches { + commutativeAccumulationWithType( + ComparableOperation.CommutativeAccumulation + .AccumulationType.SUMMATION + ) { + index(1) { } + } + } + } + } + + @Test + fun testComparableOperationSubject_matchesWithValidOperation() { + val operation = ComparableOperation.newBuilder() + .setNonCommutativeOperation( + ComparableOperation.NonCommutativeOperation.newBuilder() + .setExponentiation( + ComparableOperation.NonCommutativeOperation.BinaryOperation.newBuilder() + .setLeftOperand(createConstantOperation(2)) + .setRightOperand(createConstantOperation(3)) + ) + ) + .build() + + ComparableOperationSubject.assertThat(operation).hasStructureThatMatches { + nonCommutativeOperation { + exponentiation { + leftOperand { + constantTerm { + withValueThat().isIntegerThat().isEqualTo(2) + } + } + rightOperand { + constantTerm { + withValueThat().isIntegerThat().isEqualTo(3) + } + } + } + } + } + } + + @Test + fun testComparableOperationSubject_exponentiationFailsWithInvalidOperation() { + val operation = ComparableOperation.newBuilder() + .setNonCommutativeOperation( + ComparableOperation.NonCommutativeOperation.newBuilder() + .setSquareRoot(createConstantOperation(4)) + ) + .build() + assertThrows(AssertionError::class.java) { + ComparableOperationSubject.assertThat(operation).hasStructureThatMatches { + nonCommutativeOperation { + exponentiation { } + } + } + } + } + + @Test + fun testComparableOperationSubject_squareRoot_withValidOperation() { + val operation = ComparableOperation.newBuilder() + .setNonCommutativeOperation( + ComparableOperation.NonCommutativeOperation.newBuilder() + .setSquareRoot(createConstantOperation(4)) + ) + .build() + + ComparableOperationSubject.assertThat(operation).hasStructureThatMatches { + nonCommutativeOperation { + squareRootWithArgument { + constantTerm { + withValueThat().isIntegerThat().isEqualTo(4) + } + } + } + } + } + + @Test + fun testComparableOperationSubject_squareRoot_failsWithInvalidOperation() { + val operation = ComparableOperation.newBuilder() + .setNonCommutativeOperation( + ComparableOperation.NonCommutativeOperation.newBuilder() + .setExponentiation( + ComparableOperation.NonCommutativeOperation.BinaryOperation.newBuilder() + .setLeftOperand(createConstantOperation(2)) + .setRightOperand(createConstantOperation(3)) + ) + ) + .build() + assertThrows(AssertionError::class.java) { + ComparableOperationSubject.assertThat(operation).hasStructureThatMatches { + nonCommutativeOperation { + squareRootWithArgument { } + } + } + } + } + + @Test + fun testComparableOperationSubject_binaryOperation_failsWithInvalidLeftOperand() { + val operation = ComparableOperation.newBuilder() + .setNonCommutativeOperation( + ComparableOperation.NonCommutativeOperation.newBuilder() + .setExponentiation( + ComparableOperation.NonCommutativeOperation.BinaryOperation.newBuilder() + .setRightOperand(createConstantOperation(3)) + ) + ) + .build() + assertThrows(AssertionError::class.java) { + ComparableOperationSubject.assertThat(operation).hasStructureThatMatches { + nonCommutativeOperation { + exponentiation { + leftOperand { + constantTerm { + withValueThat().isIntegerThat().isEqualTo(2) + } + } + } + } + } + } + } + + @Test + fun testComparableOperationSubject_binaryOperation_failsWithInvalidRightOperand() { + val operation = ComparableOperation.newBuilder() + .setNonCommutativeOperation( + ComparableOperation.NonCommutativeOperation.newBuilder() + .setExponentiation( + ComparableOperation.NonCommutativeOperation.BinaryOperation.newBuilder() + .setLeftOperand(createConstantOperation(2)) + ) + ) + .build() + assertThrows(AssertionError::class.java) { + ComparableOperationSubject.assertThat(operation).hasStructureThatMatches { + nonCommutativeOperation { + exponentiation { + rightOperand { + constantTerm { + withValueThat().isIntegerThat().isEqualTo(3) + } + } + } + } + } + } + } + + @Test + fun testComparableOperationSubject_checksConstantTerm_withValidValue() { + val operation = createConstantOperation(42) + + ComparableOperationSubject.assertThat(operation).hasStructureThatMatches { + constantTerm { + withValueThat().isIntegerThat().isEqualTo(42) + } + } + } + + @Test + fun testComparableOperationSubject_constantTerm_failsWithInvalidType() { + val operation = createVariableOperation("x") + assertThrows(AssertionError::class.java) { + ComparableOperationSubject.assertThat(operation).hasStructureThatMatches { + constantTerm { + withValueThat().isIntegerThat().isEqualTo(42) + } + } + } + } + + @Test + fun testComparableOperationSubject_validatesVariableTerm() { + val operation = createVariableOperation("x") + + ComparableOperationSubject.assertThat(operation).hasStructureThatMatches { + variableTerm { + withNameThat().isEqualTo("x") + } + } + } + + @Test(expected = AssertionError::class) + fun testComparableOperationSubject_variableTerm_failWithInvalidType() { + val operation = createConstantOperation(42) + + ComparableOperationSubject.assertThat(operation).hasStructureThatMatches { + variableTerm { + withNameThat().isEqualTo("x") + } + } + } + + @Test + fun testComparableOperationSubject_complexExpression_withNestedOperations() { + val operation = createCommutativeAccumulation( + ComparableOperation.CommutativeAccumulation.AccumulationType.PRODUCT, + ComparableOperation.newBuilder() + .setNonCommutativeOperation( + ComparableOperation.NonCommutativeOperation.newBuilder() + .setExponentiation( + ComparableOperation.NonCommutativeOperation.BinaryOperation.newBuilder() + .setLeftOperand(createConstantOperation(2)) + .setRightOperand(createConstantOperation(3)) + ) + ) + .build(), + ComparableOperation.newBuilder() + .setNonCommutativeOperation( + ComparableOperation.NonCommutativeOperation.newBuilder() + .setSquareRoot(createConstantOperation(4)) + ) + .build(), + createVariableOperation("x") + ) + + ComparableOperationSubject.assertThat(operation).hasStructureThatMatches { + commutativeAccumulationWithType( + ComparableOperation.CommutativeAccumulation + .AccumulationType.PRODUCT + ) { + hasOperandCountThat().isEqualTo(3) + index(0) { + nonCommutativeOperation { + exponentiation { + leftOperand { + constantTerm { + withValueThat().isIntegerThat().isEqualTo(2) + } + } + rightOperand { + constantTerm { + withValueThat().isIntegerThat().isEqualTo(3) + } + } + } + } + } + index(1) { + nonCommutativeOperation { + squareRootWithArgument { + constantTerm { + withValueThat().isIntegerThat().isEqualTo(4) + } + } + } + } + index(2) { + variableTerm { + withNameThat().isEqualTo("x") + } + } + } + } + } +}