From 45257da323b77648373edd52b4997bdffe261c64 Mon Sep 17 00:00:00 2001 From: Ayush Yadav <143514610+theayushyadav11@users.noreply.github.com> Date: Tue, 4 Mar 2025 05:32:31 +0530 Subject: [PATCH] Fixes #4098: Added tests for ComparableOperationSubjectTest (#5673) Fixes #4098: This pull request includes changes to add tests for the `ComparableOperationSubject` class and update the build configuration to include these tests. The most important changes are: ### Test Additions: * Added tests for `ComparableOperationSubject` ### Build Configuration: * Added a new `oppia_android_test` target for `ComparableOperationSubjectTest` in the `BUILD.bazel` file to include the necessary dependencies and configuration for running the tests. #### Screenshot of the passing tests. ![image](https://github.com/user-attachments/assets/138a2460-12ff-46d2-8d34-3e503960a381) ## Essential Checklist - [x] The PR title and explanation each start with "Fix #bugnum: " (If this PR fixes part of an issue, prefix the title with "Fix part of #bugnum: ...".) - [x] Any changes to [scripts/assets](https://github.com/oppia/oppia-android/tree/develop/scripts/assets) files have their rationale included in the PR explanation. - [x] The PR follows the [style guide](https://github.com/oppia/oppia-android/wiki/Coding-style-guide). - [x] The PR does not contain any unnecessary code changes from Android Studio ([reference](https://github.com/oppia/oppia-android/wiki/Guidance-on-submitting-a-PR#undo-unnecessary-changes)). - [x] The PR is made from a branch that's **not** called "develop" and is up-to-date with "develop". - [x] The PR is **assigned** to the appropriate reviewers ([reference](https://github.com/oppia/oppia-android/wiki/Guidance-on-submitting-a-PR#clarification-regarding-assignees-and-reviewers-section)). --------- Co-authored-by: theayushyadav11 --- scripts/assets/test_file_exemptions.textproto | 4 - .../math/ComparableOperationSubject.kt | 2 - .../oppia/android/testing/math/BUILD.bazel | 16 + .../math/ComparableOperationSubjectTest.kt | 431 ++++++++++++++++++ 4 files changed, 447 insertions(+), 6 deletions(-) create mode 100644 testing/src/test/java/org/oppia/android/testing/math/ComparableOperationSubjectTest.kt diff --git a/scripts/assets/test_file_exemptions.textproto b/scripts/assets/test_file_exemptions.textproto index 2b4731054d5..366454b66b3 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/mockito/MockitoKotlinHelper.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 cdc91cd8b0f..dce7fbafab7 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 @@ -112,3 +112,19 @@ 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 = [ + "//model/src/main/proto:math_java_proto_lite", + "//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..ca959aa9647 --- /dev/null +++ b/testing/src/test/java/org/oppia/android/testing/math/ComparableOperationSubjectTest.kt @@ -0,0 +1,431 @@ +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 +import org.oppia.android.testing.math.ComparableOperationSubject.Companion.assertThat + +/** 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) + + assertThat(operation).hasStructureThatMatches { + constantTerm { + withValueThat().isIntegerThat().isEqualTo(42) + } + } + } + + @Test + fun testComparableOperationSubject_failsWithInvalidStructure() { + val operation = createConstantOperation(42) + assertThrows(AssertionError::class.java) { + assertThat(operation).hasStructureThatMatches { + variableTerm { + withNameThat().isEqualTo("x") + } + } + } + } + + @Test + fun testComparableOperationSubject_hasNegatedProperty_matchesFalse() { + val operation = createConstantOperation(42) + + assertThat(operation).hasStructureThatMatches { + hasNegatedPropertyThat().isFalse() + } + } + + @Test + fun testComparableOperationSubject_hasNegatedPropertyThat_matchesTrue() { + val operation = ComparableOperation.newBuilder() + .setConstantTerm(Real.newBuilder().setInteger(42)) + .setIsNegated(true) + .build() + + assertThat(operation).hasStructureThatMatches { + hasNegatedPropertyThat().isTrue() + } + } + + @Test + fun testComparableOperationSubject_hasInvertedProperty_matchesFalse() { + val operation = createConstantOperation(42) + + assertThat(operation).hasStructureThatMatches { + hasInvertedPropertyThat().isFalse() + } + } + + @Test + fun testComparableOperationSubject_hasInvertedProperty_matchesTrue() { + val operation = ComparableOperation.newBuilder() + .setConstantTerm(Real.newBuilder().setInteger(42)) + .setIsInverted(true) + .build() + + assertThat(operation).hasStructureThatMatches { + hasInvertedPropertyThat().isTrue() + } + } + + @Test + fun testComparableOperationSubject_commutativeAccumulation_withValidSummation() { + val operation = createCommutativeAccumulation( + ComparableOperation.CommutativeAccumulation.AccumulationType.SUMMATION, + createConstantOperation(1), + createConstantOperation(2) + ) + + 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_withEmpty_commutativeAccumulation_hasCorrectStructre() { + val operation = createCommutativeAccumulation( + ComparableOperation.CommutativeAccumulation.AccumulationType.SUMMATION + ) + + assertThat(operation).hasStructureThatMatches { + commutativeAccumulationWithType( + ComparableOperation.CommutativeAccumulation + .AccumulationType.SUMMATION + ) { + hasOperandCountThat().isEqualTo(0) + } + } + } + + @Test + fun testComparableOperationSubject_commutativeAccumulation_failsWithInvalidType() { + val operation = createConstantOperation(42) + assertThrows(AssertionError::class.java) { + 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) { + 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() + + assertThat(operation).hasStructureThatMatches { + nonCommutativeOperation { + exponentiation { + leftOperand { + constantTerm { + withValueThat().isIntegerThat().isEqualTo(2) + } + } + rightOperand { + constantTerm { + withValueThat().isIntegerThat().isEqualTo(3) + } + } + } + } + } + } + + @Test + fun testComparableOperationSubject_exponentiation_failsWithInvalidOperation() { + val operation = ComparableOperation.newBuilder() + .setNonCommutativeOperation( + ComparableOperation.NonCommutativeOperation.newBuilder() + .setSquareRoot(createConstantOperation(4)) + ) + .build() + assertThrows(AssertionError::class.java) { + assertThat(operation).hasStructureThatMatches { + nonCommutativeOperation { + exponentiation { } + } + } + } + } + + @Test + fun testComparableOperationSubject_squareRoot_withValidOperation_hasCorrectStructure() { + val operation = ComparableOperation.newBuilder() + .setNonCommutativeOperation( + ComparableOperation.NonCommutativeOperation.newBuilder() + .setSquareRoot(createConstantOperation(4)) + ) + .build() + + 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) { + 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) { + 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) { + assertThat(operation).hasStructureThatMatches { + nonCommutativeOperation { + exponentiation { + rightOperand { + constantTerm { + withValueThat().isIntegerThat().isEqualTo(3) + } + } + } + } + } + } + } + + @Test + fun testComparableOperationSubject_checksConstantTerm_withValidValue() { + val operation = createConstantOperation(42) + + assertThat(operation).hasStructureThatMatches { + constantTerm { + withValueThat().isIntegerThat().isEqualTo(42) + } + } + } + + @Test + fun testComparableOperationSubject_constantTerm_failsWithInvalidType() { + val operation = createVariableOperation("x") + assertThrows(AssertionError::class.java) { + assertThat(operation).hasStructureThatMatches { + constantTerm { + withValueThat().isIntegerThat().isEqualTo(42) + } + } + } + } + + @Test + fun testComparableOperationSubject_withVariableTerm_hasExpectedName() { + val operation = createVariableOperation("x") + + assertThat(operation).hasStructureThatMatches { + variableTerm { + withNameThat().isEqualTo("x") + } + } + } + + @Test + fun testComparableOperationSubject_variableTerm_failWithInvalidType() { + val operation = createConstantOperation(42) + + assertThrows(AssertionError::class.java) { + assertThat(operation).hasStructureThatMatches { + variableTerm { + withNameThat().isEqualTo("x") + } + } + } + } + + @Test + fun testComparableOperationSubject_complexExpression_withNestedOperations_hasCorrectStructure() { + 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") + ) + + 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") + } + } + } + } + } +}