From 3936364a494dfd199c0d41d657fc5e2012c5f3e6 Mon Sep 17 00:00:00 2001 From: XichengSpencer <74568012+XichengSpencer@users.noreply.github.com> Date: Tue, 4 Jul 2023 01:01:51 -0400 Subject: [PATCH 01/13] Resolve the test build error --- app/build.gradle | 1 + 1 file changed, 1 insertion(+) diff --git a/app/build.gradle b/app/build.gradle index 34aeccd28b1..71b759c6475 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -210,6 +210,7 @@ dependencies { 'androidx.test.espresso:espresso-core:3.2.0', 'androidx.test.espresso:espresso-intents:3.1.0', 'androidx.test.ext:junit:1.1.1', + 'androidx.test.ext:truth:1.4.0', 'com.github.bumptech.glide:mocks:4.11.0', 'com.google.truth:truth:1.1.3', 'androidx.work:work-testing:2.4.0', From ed714a6331816b9d1d2ca6508461d8781b4304a4 Mon Sep 17 00:00:00 2001 From: XichengSpencer <74568012+XichengSpencer@users.noreply.github.com> Date: Tue, 12 Sep 2023 16:27:21 -0400 Subject: [PATCH 02/13] Change 1 concatenate string to 3 seperate text view --- .../drawer/NavigationDrawerHeaderViewModel.kt | 36 ++++++++------ .../layout/nav_header_navigation_drawer.xml | 47 +++++++++++++++---- 2 files changed, 59 insertions(+), 24 deletions(-) diff --git a/app/src/main/java/org/oppia/android/app/drawer/NavigationDrawerHeaderViewModel.kt b/app/src/main/java/org/oppia/android/app/drawer/NavigationDrawerHeaderViewModel.kt index b46e7a63275..f9cf43ffdea 100644 --- a/app/src/main/java/org/oppia/android/app/drawer/NavigationDrawerHeaderViewModel.kt +++ b/app/src/main/java/org/oppia/android/app/drawer/NavigationDrawerHeaderViewModel.kt @@ -22,7 +22,10 @@ class NavigationDrawerHeaderViewModel @Inject constructor( val profile = ObservableField(Profile.getDefaultInstance()) private var ongoingTopicCount = DEFAULT_ONGOING_TOPIC_COUNT private var completedStoryCount = DEFAULT_COMPLETED_STORY_COUNT - val profileProgressText: ObservableField = ObservableField(computeProfileProgressText()) + val profileTopicProgressText: ObservableField = + ObservableField(computeProfileTopicProgressText()) + val profileStoryProgressText: ObservableField = + ObservableField(computeProfileStoryProgressText()) fun onHeaderClicked() { routeToProfileProgressListener.routeToProfileProgress(profile.get()!!.id.internalId) @@ -30,25 +33,30 @@ class NavigationDrawerHeaderViewModel @Inject constructor( fun setOngoingTopicProgress(ongoingTopicCount: Int) { this.ongoingTopicCount = ongoingTopicCount - profileProgressText.set(computeProfileProgressText()) + profileTopicProgressText.set(computeProfileTopicProgressText()) } fun setCompletedStoryProgress(completedStoryCount: Int) { this.completedStoryCount = completedStoryCount - profileProgressText.set(computeProfileProgressText()) + profileStoryProgressText.set(computeProfileStoryProgressText()) } - private fun computeProfileProgressText(): String { + private fun computeProfileStoryProgressText(): String { // TODO(#3843): Either combine these strings into one or use separate views to display them. - val completedStoryCountText = - resourceHandler.getQuantityStringInLocaleWithWrapping( - R.plurals.completed_story_count, completedStoryCount, completedStoryCount.toString() - ) - val ongoingTopicCountText = - resourceHandler.getQuantityStringInLocaleWithWrapping( - R.plurals.ongoing_topic_count, ongoingTopicCount, ongoingTopicCount.toString() - ) - val barSeparator = resourceHandler.getStringInLocale(R.string.bar_separator) - return "$completedStoryCountText$barSeparator$ongoingTopicCountText" + return resourceHandler.getQuantityStringInLocaleWithWrapping( + R.plurals.completed_story_count, + completedStoryCount, + completedStoryCount.toString() + ) + } + + fun getBarSeparator() = resourceHandler.getStringInLocale(R.string.bar_separator) + + private fun computeProfileTopicProgressText(): String { + return resourceHandler.getQuantityStringInLocaleWithWrapping( + R.plurals.ongoing_topic_count, + ongoingTopicCount, + ongoingTopicCount.toString() + ) } } diff --git a/app/src/main/res/layout/nav_header_navigation_drawer.xml b/app/src/main/res/layout/nav_header_navigation_drawer.xml index eb9d9a0ccad..ef9376f5d36 100644 --- a/app/src/main/res/layout/nav_header_navigation_drawer.xml +++ b/app/src/main/res/layout/nav_header_navigation_drawer.xml @@ -43,17 +43,44 @@ android:text="@{viewModel.profile.name}" android:textColor="@color/component_color_shared_secondary_4_text_color" android:textSize="14sp" /> - - + android:orientation="horizontal"> + + + + From f1c1bac9d9ecc80c506c3b80b4930744264bc655 Mon Sep 17 00:00:00 2001 From: XichengSpencer <74568012+XichengSpencer@users.noreply.github.com> Date: Tue, 12 Sep 2023 16:28:41 -0400 Subject: [PATCH 03/13] format code --- app/src/main/res/layout/nav_header_navigation_drawer.xml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/app/src/main/res/layout/nav_header_navigation_drawer.xml b/app/src/main/res/layout/nav_header_navigation_drawer.xml index ef9376f5d36..d85e97e337b 100644 --- a/app/src/main/res/layout/nav_header_navigation_drawer.xml +++ b/app/src/main/res/layout/nav_header_navigation_drawer.xml @@ -27,10 +27,10 @@ + + + + Date: Thu, 14 Sep 2023 12:06:23 -0400 Subject: [PATCH 04/13] Change the corresponding test. --- .../NavigationDrawerActivityProdTest.kt | 30 ++++++++++++++++--- 1 file changed, 26 insertions(+), 4 deletions(-) diff --git a/app/src/sharedTest/java/org/oppia/android/app/testing/NavigationDrawerActivityProdTest.kt b/app/src/sharedTest/java/org/oppia/android/app/testing/NavigationDrawerActivityProdTest.kt index bce54aac8a1..08512202fb7 100644 --- a/app/src/sharedTest/java/org/oppia/android/app/testing/NavigationDrawerActivityProdTest.kt +++ b/app/src/sharedTest/java/org/oppia/android/app/testing/NavigationDrawerActivityProdTest.kt @@ -256,7 +256,7 @@ class NavigationDrawerActivityProdTest { } @Test - fun testNavDrawer_openNavDrawer_oneTopicInProgress_profileProgressIsDisplayedCorrectly() { + fun testNavDrawer_openNavDrawer_oneTopicInProgress_profileStoryProgressIsDisplayedCorrectly() { storyProfileTestHelper.markCompletedRatiosStory1Exp0( ProfileId.newBuilder().setInternalId( internalProfileId @@ -270,10 +270,32 @@ class NavigationDrawerActivityProdTest { it.openNavigationDrawer() onView( allOf( - withId(R.id.profile_progress_text_view), - isDescendantOfA(withId(R.id.header_linear_layout)) + withId(R.id.profile_story_progress_text_view), + isDescendantOfA(withId(R.id.progress_linear_layout)) + ) + ).check(matches(withText("1 Story Completed"))) + } + } + + @Test + fun testNavDrawer_openNavDrawer_oneTopicInProgress_profileTopicProgressIsDisplayedCorrectly() { + storyProfileTestHelper.markCompletedRatiosStory1Exp0( + ProfileId.newBuilder().setInternalId( + internalProfileId + ).build(), + timestampOlderThanOneWeek = false + ) + launch( + createNavigationDrawerActivityIntent(internalProfileId) + ).use { + testCoroutineDispatchers.runCurrent() + it.openNavigationDrawer() + onView( + allOf( + withId(R.id.profile_topic_progress_text_view), + isDescendantOfA(withId(R.id.progress_linear_layout)) ) - ).check(matches(withText("1 Story Completed | 1 Topic in Progress"))) + ).check(matches(withText("1 Topic in Progress"))) } } From 9c56e24721105874f732cbab2d39389a8c65fe16 Mon Sep 17 00:00:00 2001 From: XichengSpencer <74568012+XichengSpencer@users.noreply.github.com> Date: Wed, 20 Sep 2023 16:13:30 -0400 Subject: [PATCH 05/13] Remove TODO --- .../oppia/android/app/drawer/NavigationDrawerHeaderViewModel.kt | 1 - 1 file changed, 1 deletion(-) diff --git a/app/src/main/java/org/oppia/android/app/drawer/NavigationDrawerHeaderViewModel.kt b/app/src/main/java/org/oppia/android/app/drawer/NavigationDrawerHeaderViewModel.kt index f9cf43ffdea..d75c0d03287 100644 --- a/app/src/main/java/org/oppia/android/app/drawer/NavigationDrawerHeaderViewModel.kt +++ b/app/src/main/java/org/oppia/android/app/drawer/NavigationDrawerHeaderViewModel.kt @@ -42,7 +42,6 @@ class NavigationDrawerHeaderViewModel @Inject constructor( } private fun computeProfileStoryProgressText(): String { - // TODO(#3843): Either combine these strings into one or use separate views to display them. return resourceHandler.getQuantityStringInLocaleWithWrapping( R.plurals.completed_story_count, completedStoryCount, From 6fe9746769f423f8becc716d978458f2e98b6fa7 Mon Sep 17 00:00:00 2001 From: XichengSpencer <74568012+XichengSpencer@users.noreply.github.com> Date: Wed, 15 Nov 2023 16:37:00 -0500 Subject: [PATCH 06/13] remove testAddProfileActivity_inputPin_configChange_downloadAccessSwitchIsOn() as discussed , fix enable download access logic ,improve testAddProfileActivity_configChange_inputShortPin_create_pinLengthError() but still flaky --- .../profile/AddProfileActivityPresenter.kt | 2 +- .../main/res/layout/add_profile_activity.xml | 1 + .../app/profile/AddProfileActivityTest.kt | 141 ++++++++---------- 3 files changed, 61 insertions(+), 83 deletions(-) diff --git a/app/src/main/java/org/oppia/android/app/profile/AddProfileActivityPresenter.kt b/app/src/main/java/org/oppia/android/app/profile/AddProfileActivityPresenter.kt index 75c8cc2e014..744aaa0cb50 100644 --- a/app/src/main/java/org/oppia/android/app/profile/AddProfileActivityPresenter.kt +++ b/app/src/main/java/org/oppia/android/app/profile/AddProfileActivityPresenter.kt @@ -63,7 +63,7 @@ class AddProfileActivityPresenter @Inject constructor( lifecycleOwner = activity viewModel = profileViewModel } - if (!enableDownloadsSupport.value) { + if (enableDownloadsSupport.value) { binding.addProfileActivityAllowDownloadConstraintLayout.setOnClickListener { allowDownloadAccess = !allowDownloadAccess binding.addProfileActivityAllowDownloadSwitch.isChecked = allowDownloadAccess diff --git a/app/src/main/res/layout/add_profile_activity.xml b/app/src/main/res/layout/add_profile_activity.xml index 6a0c53c3282..ee47a0cfec7 100644 --- a/app/src/main/res/layout/add_profile_activity.xml +++ b/app/src/main/res/layout/add_profile_activity.xml @@ -233,6 +233,7 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="60dp" + android:focusable="true" android:background="@{viewModel.isButtonActive() ? @drawable/state_button_primary_background : @drawable/start_button_transparent_background}" android:enabled="@{viewModel.isButtonActive()}" android:gravity="center" diff --git a/app/src/sharedTest/java/org/oppia/android/app/profile/AddProfileActivityTest.kt b/app/src/sharedTest/java/org/oppia/android/app/profile/AddProfileActivityTest.kt index 605a1c18cc7..6ead5d8438b 100644 --- a/app/src/sharedTest/java/org/oppia/android/app/profile/AddProfileActivityTest.kt +++ b/app/src/sharedTest/java/org/oppia/android/app/profile/AddProfileActivityTest.kt @@ -17,6 +17,7 @@ import androidx.test.espresso.action.ViewActions.click import androidx.test.espresso.action.ViewActions.closeSoftKeyboard import androidx.test.espresso.action.ViewActions.pressImeActionButton import androidx.test.espresso.action.ViewActions.scrollTo +import androidx.test.espresso.action.ViewActions.swipeUp import androidx.test.espresso.assertion.ViewAssertions.matches import androidx.test.espresso.intent.Intents import androidx.test.espresso.intent.Intents.intended @@ -90,7 +91,6 @@ import org.oppia.android.domain.oppialogger.analytics.ApplicationLifecycleModule import org.oppia.android.domain.oppialogger.analytics.CpuPerformanceSnapshotterModule import org.oppia.android.domain.oppialogger.logscheduler.MetricLogSchedulerModule import org.oppia.android.domain.oppialogger.loguploader.LogReportWorkerModule -import org.oppia.android.domain.platformparameter.PlatformParameterModule import org.oppia.android.domain.platformparameter.PlatformParameterSingletonModule import org.oppia.android.domain.question.QuestionModule import org.oppia.android.domain.topic.PrimeTopicAssetsControllerModule @@ -102,6 +102,7 @@ import org.oppia.android.testing.espresso.TextInputAction.Companion.hasErrorText import org.oppia.android.testing.espresso.TextInputAction.Companion.hasHelperText import org.oppia.android.testing.espresso.TextInputAction.Companion.hasNoErrorText import org.oppia.android.testing.junit.InitializeDefaultLocaleRule +import org.oppia.android.testing.platformparameter.TestPlatformParameterModule import org.oppia.android.testing.profile.ProfileTestHelper import org.oppia.android.testing.robolectric.RobolectricModule import org.oppia.android.testing.threading.TestCoroutineDispatchers @@ -209,7 +210,8 @@ class AddProfileActivityTest { isDescendantOfA(withId(R.id.add_profile_activity_user_name)) ) ).perform( - editTextInputAction.appendText("test"), closeSoftKeyboard() + editTextInputAction.appendText("test"), + closeSoftKeyboard() ) testCoroutineDispatchers.runCurrent() onView(withId(R.id.add_profile_activity_pin_check_box)).perform(click()) @@ -275,7 +277,8 @@ class AddProfileActivityTest { isDescendantOfA(withId(R.id.add_profile_activity_user_name)) ) ).perform( - editTextInputAction.appendText("test"), closeSoftKeyboard() + editTextInputAction.appendText("test"), + closeSoftKeyboard() ) testCoroutineDispatchers.runCurrent() onView(withId(R.id.add_profile_activity_create_button)).perform(scrollTo()) @@ -296,7 +299,8 @@ class AddProfileActivityTest { isDescendantOfA(withId(R.id.add_profile_activity_user_name)) ) ).perform(scrollTo()).perform( - editTextInputAction.appendText("test"), closeSoftKeyboard() + editTextInputAction.appendText("test"), + closeSoftKeyboard() ) testCoroutineDispatchers.runCurrent() onView(withId(R.id.add_profile_activity_create_button)).perform(scrollTo()) @@ -472,7 +476,7 @@ class AddProfileActivityTest { } @Test - fun testAddProfileActivity_configChange_createIsDisbaled() { + fun testAddProfileActivity_configChange_createIsDisabled() { launch(AddProfileActivity::class.java).use { onView(isRoot()).perform(orientationLandscape()) onView(withId(R.id.add_profile_activity_create_button)).perform(scrollTo()) @@ -490,7 +494,8 @@ class AddProfileActivityTest { isDescendantOfA(withId(R.id.add_profile_activity_user_name)) ) ).perform( - editTextInputAction.appendText("Rajat"), closeSoftKeyboard() + editTextInputAction.appendText("Rajat"), + closeSoftKeyboard() ) onView(withId(R.id.add_profile_activity_create_button)).perform(scrollTo()) onView(withId(R.id.add_profile_activity_create_button)).check(matches(isEnabled())) @@ -507,7 +512,8 @@ class AddProfileActivityTest { isDescendantOfA(withId(R.id.add_profile_activity_user_name)) ) ).perform( - editTextInputAction.appendText("Rajat"), closeSoftKeyboard() + editTextInputAction.appendText("Rajat"), + closeSoftKeyboard() ) onView(isRoot()).perform(orientationLandscape()) onView(withId(R.id.add_profile_activity_create_button)).perform(scrollTo()) @@ -525,7 +531,8 @@ class AddProfileActivityTest { isDescendantOfA(withId(R.id.add_profile_activity_user_name)) ) ).perform( - editTextInputAction.appendText("Admin"), closeSoftKeyboard() + editTextInputAction.appendText("Admin"), + closeSoftKeyboard() ) testCoroutineDispatchers.runCurrent() onView(withId(R.id.add_profile_activity_create_button)).perform(scrollTo()) @@ -553,7 +560,8 @@ class AddProfileActivityTest { isDescendantOfA(withId(R.id.add_profile_activity_user_name)) ) ).perform(scrollTo()).perform( - editTextInputAction.appendText("Admin"), closeSoftKeyboard() + editTextInputAction.appendText("Admin"), + closeSoftKeyboard() ) testCoroutineDispatchers.runCurrent() onView(withId(R.id.add_profile_activity_create_button)).perform(scrollTo()) @@ -580,7 +588,8 @@ class AddProfileActivityTest { isDescendantOfA(withId(R.id.add_profile_activity_user_name)) ) ).perform( - editTextInputAction.appendText("Admin"), closeSoftKeyboard() + editTextInputAction.appendText("Admin"), + closeSoftKeyboard() ) testCoroutineDispatchers.runCurrent() onView(withId(R.id.add_profile_activity_create_button)).perform(scrollTo()) @@ -592,7 +601,8 @@ class AddProfileActivityTest { isDescendantOfA(withId(R.id.add_profile_activity_user_name)) ) ).perform( - editTextInputAction.appendText(" "), closeSoftKeyboard() + editTextInputAction.appendText(" "), + closeSoftKeyboard() ) testCoroutineDispatchers.runCurrent() onView(withId(R.id.add_profile_activity_user_name)) @@ -613,7 +623,8 @@ class AddProfileActivityTest { isDescendantOfA(withId(R.id.add_profile_activity_user_name)) ) ).perform(scrollTo()).perform( - editTextInputAction.appendText("Admin"), closeSoftKeyboard() + editTextInputAction.appendText("Admin"), + closeSoftKeyboard() ) testCoroutineDispatchers.runCurrent() onView(withId(R.id.add_profile_activity_create_button)).perform(scrollTo()) @@ -631,7 +642,8 @@ class AddProfileActivityTest { isDescendantOfA(withId(R.id.add_profile_activity_user_name)) ) ).perform( - editTextInputAction.appendText(" "), closeSoftKeyboard() + editTextInputAction.appendText(" "), + closeSoftKeyboard() ) testCoroutineDispatchers.runCurrent() onView(withId(R.id.add_profile_activity_user_name)) @@ -648,7 +660,8 @@ class AddProfileActivityTest { isDescendantOfA(withId(R.id.add_profile_activity_user_name)) ) ).perform( - editTextInputAction.appendText("123"), closeSoftKeyboard() + editTextInputAction.appendText("123"), + closeSoftKeyboard() ) testCoroutineDispatchers.runCurrent() onView(withId(R.id.add_profile_activity_create_button)).perform(scrollTo()) @@ -677,7 +690,8 @@ class AddProfileActivityTest { isDescendantOfA(withId(R.id.add_profile_activity_user_name)) ) ).perform( - editTextInputAction.appendText("123"), closeSoftKeyboard() + editTextInputAction.appendText("123"), + closeSoftKeyboard() ) testCoroutineDispatchers.runCurrent() onView(withId(R.id.add_profile_activity_create_button)).perform(scrollTo()) @@ -704,7 +718,8 @@ class AddProfileActivityTest { isDescendantOfA(withId(R.id.add_profile_activity_user_name)) ) ).perform( - editTextInputAction.appendText("123"), closeSoftKeyboard() + editTextInputAction.appendText("123"), + closeSoftKeyboard() ) testCoroutineDispatchers.runCurrent() onView(withId(R.id.add_profile_activity_create_button)).perform(scrollTo()) @@ -716,7 +731,8 @@ class AddProfileActivityTest { isDescendantOfA(withId(R.id.add_profile_activity_user_name)) ) ).perform( - editTextInputAction.appendText(" "), closeSoftKeyboard() + editTextInputAction.appendText(" "), + closeSoftKeyboard() ) testCoroutineDispatchers.runCurrent() onView(withId(R.id.add_profile_activity_user_name)) @@ -735,7 +751,8 @@ class AddProfileActivityTest { isDescendantOfA(withId(R.id.add_profile_activity_user_name)) ) ).perform(scrollTo()).perform( - editTextInputAction.appendText("123"), closeSoftKeyboard() + editTextInputAction.appendText("123"), + closeSoftKeyboard() ) testCoroutineDispatchers.runCurrent() onView(withId(R.id.add_profile_activity_create_button)).perform(scrollTo()) @@ -753,7 +770,8 @@ class AddProfileActivityTest { isDescendantOfA(withId(R.id.add_profile_activity_user_name)) ) ).perform( - editTextInputAction.appendText(" "), closeSoftKeyboard() + editTextInputAction.appendText(" "), + closeSoftKeyboard() ) testCoroutineDispatchers.runCurrent() onView(withId(R.id.add_profile_activity_user_name)) @@ -771,7 +789,8 @@ class AddProfileActivityTest { isDescendantOfA(withId(R.id.add_profile_activity_user_name)) ) ).perform( - editTextInputAction.appendText("test"), closeSoftKeyboard() + editTextInputAction.appendText("test"), + closeSoftKeyboard() ) testCoroutineDispatchers.runCurrent() onView(withId(R.id.add_profile_activity_pin_check_box)).perform(click()) @@ -799,8 +818,9 @@ class AddProfileActivityTest { } } + @Ignore("Flaky test") + // TODO(#3363): Test passes on Pixel3a sometimes and fails on Pixel3. @Test - @Ignore("Flaky test") // TODO(#3363): Test passes on Pixel3a sometimes and fails on Pixel3. fun testAddProfileActivity_configChange_inputShortPin_create_pinLengthError() { launch(AddProfileActivity::class.java).use { testCoroutineDispatchers.runCurrent() @@ -811,7 +831,8 @@ class AddProfileActivityTest { isDescendantOfA(withId(R.id.add_profile_activity_user_name)) ) ).perform(scrollTo()).perform( - editTextInputAction.appendText("test"), closeSoftKeyboard() + editTextInputAction.appendText("test"), + closeSoftKeyboard() ) testCoroutineDispatchers.runCurrent() onView(withId(R.id.add_profile_activity_pin_check_box)).perform(scrollTo()) @@ -833,7 +854,9 @@ class AddProfileActivityTest { ) testCoroutineDispatchers.runCurrent() onView(withId(R.id.add_profile_activity_create_button)).perform(scrollTo()) + onView(withId(R.id.add_profile_activity_scroll_view)).perform(swipeUp()) onView(withId(R.id.add_profile_activity_create_button)).perform(click()) + onView(withId(R.id.add_profile_activity_pin)).perform(scrollTo()) onView(withId(R.id.add_profile_activity_pin)) .check( matches( @@ -868,16 +891,19 @@ class AddProfileActivityTest { isDescendantOfA(withId(R.id.add_profile_activity_pin)) ) ).perform(scrollTo()).perform( - editTextInputAction.appendText("3"), closeSoftKeyboard() + editTextInputAction.appendText("3"), + closeSoftKeyboard() ) testCoroutineDispatchers.runCurrent() onView(withId(R.id.add_profile_activity_pin)) + .perform(scrollTo()) .check(matches(hasNoErrorText())) } } + @Ignore("Flaky test") + // TODO(#3363): Test passes on Pixel3a sometimes and fails on Pixel3. @Test - @Ignore("Flaky test") // TODO(#3363): Test passes on Pixel3a sometimes and fails on Pixel3. fun testAddProfileActivity_configChange_inputShortPin_create_inputPin_errorIsCleared() { launch(AddProfileActivity::class.java).use { onView(isRoot()).perform(orientationLandscape()) @@ -922,7 +948,8 @@ class AddProfileActivityTest { isDescendantOfA(withId(R.id.add_profile_activity_user_name)) ) ).perform( - editTextInputAction.appendText("test"), closeSoftKeyboard() + editTextInputAction.appendText("test"), + closeSoftKeyboard() ) testCoroutineDispatchers.runCurrent() onView(withId(R.id.add_profile_activity_pin_check_box)).perform(click()) @@ -968,13 +995,15 @@ class AddProfileActivityTest { launch(AddProfileActivity::class.java).use { onView(isRoot()).perform(orientationLandscape()) onView(withId(R.id.add_profile_activity_pin_check_box)).perform(scrollTo()) + onView(withId(R.id.add_profile_activity_pin_check_box)).perform(scrollTo()) onView( allOf( withId(R.id.add_profile_activity_user_name_edit_text), isDescendantOfA(withId(R.id.add_profile_activity_user_name)) ) ).perform(scrollTo()).perform( - editTextInputAction.appendText("test"), closeSoftKeyboard() + editTextInputAction.appendText("test"), + closeSoftKeyboard() ) testCoroutineDispatchers.runCurrent() onView(withId(R.id.add_profile_activity_pin_check_box)).perform(scrollTo()) @@ -1142,7 +1171,8 @@ class AddProfileActivityTest { isDescendantOfA(withId(R.id.add_profile_activity_user_name)) ) ).perform(scrollTo()).perform( - editTextInputAction.appendText("test"), closeSoftKeyboard() + editTextInputAction.appendText("test"), + closeSoftKeyboard() ) onView(withId(R.id.add_profile_activity_pin_check_box)).perform(scrollTo()) onView(withId(R.id.add_profile_activity_pin_check_box)).perform(click()) @@ -1686,6 +1716,7 @@ class AddProfileActivityTest { onView(withId(R.id.add_profile_activity_create_button)).perform(scrollTo()) onView(withId(R.id.add_profile_activity_create_button)).perform(click()) onView(isRoot()).perform(orientationLandscape()) + testCoroutineDispatchers.runCurrent() onView(withId(R.id.add_profile_activity_pin_check_box)).perform(scrollTo()) onView(withId(R.id.add_profile_activity_confirm_pin)) .check( @@ -1698,46 +1729,6 @@ class AddProfileActivityTest { } } - @Test - @Ignore("Flaky test") // TODO(#3363): Test passes on Pixel3a sometimes and fails on Pixel3. - fun testAddProfileActivity_inputPin_configChange_downloadAccessSwitchIsOn() { - launch(AddProfileActivity::class.java).use { - onView(withId(R.id.add_profile_activity_pin_check_box)).perform(click()) - onView( - allOf( - withId(R.id.add_profile_activity_pin_edit_text), - isDescendantOfA(withId(R.id.add_profile_activity_pin)) - ) - ).perform( - scrollTo(), - editTextInputAction.appendText("123"), - closeSoftKeyboard() - ) - testCoroutineDispatchers.runCurrent() - onView( - allOf( - withId(R.id.add_profile_activity_confirm_pin_edit_text), - isDescendantOfA(withId(R.id.add_profile_activity_confirm_pin)) - ) - ).perform(scrollTo()) - onView( - allOf( - withId(R.id.add_profile_activity_confirm_pin_edit_text), - isDescendantOfA(withId(R.id.add_profile_activity_confirm_pin)) - ) - ).perform( - editTextInputAction.appendText("123"), - closeSoftKeyboard() - ) - testCoroutineDispatchers.runCurrent() - onView(withId(R.id.add_profile_activity_allow_download_switch)).perform(scrollTo()) - onView(withId(R.id.add_profile_activity_allow_download_constraint_layout)).perform(click()) - onView(isRoot()).perform(orientationLandscape()) - onView(withId(R.id.add_profile_activity_allow_download_switch)).perform(scrollTo()) - onView(withId(R.id.add_profile_activity_allow_download_switch)).check(matches(isChecked())) - } - } - @Test fun testAddProfileActivity_clickInfo_infoPopupIsDisplayed() { launch(AddProfileActivity::class.java).use { @@ -1751,20 +1742,6 @@ class AddProfileActivityTest { } } - @Test - fun testAddProfileActivity_clickInfo_configChange_infoPopupIsDisplayed() { - launch(AddProfileActivity::class.java).use { - onView(withId(R.id.add_profile_activity_info_image_view)).perform(click()) - onView(isRoot()).perform(orientationLandscape()) - onView(withText(context.getString(R.string.add_profile_pin_info))).inRoot(isDialog()) - .check( - matches( - isDisplayed() - ) - ) - } - } - @Test fun testActivity_createIntent_verifyScreenNameInIntent() { val currentScreenName = createAddProfileActivityIntent().extractCurrentAppScreenName() @@ -1797,7 +1774,7 @@ class AddProfileActivityTest { @Component( modules = [ RobolectricModule::class, TestDispatcherModule::class, ApplicationModule::class, - PlatformParameterModule::class, PlatformParameterSingletonModule::class, + TestPlatformParameterModule::class, PlatformParameterSingletonModule::class, LoggerModule::class, ContinueModule::class, FractionInputModule::class, ItemSelectionInputModule::class, MultipleChoiceInputModule::class, NumberWithUnitsRuleModule::class, NumericInputRuleModule::class, TextInputRuleModule::class, From 40c44dfa31aaa206ba1d850000c58e690a56a011 Mon Sep 17 00:00:00 2001 From: XichengSpencer <74568012+XichengSpencer@users.noreply.github.com> Date: Thu, 7 Dec 2023 12:06:33 -0500 Subject: [PATCH 07/13] Add comment to explain the negating logic --- .../org/oppia/android/app/profile/AddProfileActivityPresenter.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/app/src/main/java/org/oppia/android/app/profile/AddProfileActivityPresenter.kt b/app/src/main/java/org/oppia/android/app/profile/AddProfileActivityPresenter.kt index 744aaa0cb50..d138419c68d 100644 --- a/app/src/main/java/org/oppia/android/app/profile/AddProfileActivityPresenter.kt +++ b/app/src/main/java/org/oppia/android/app/profile/AddProfileActivityPresenter.kt @@ -65,6 +65,7 @@ class AddProfileActivityPresenter @Inject constructor( } if (enableDownloadsSupport.value) { binding.addProfileActivityAllowDownloadConstraintLayout.setOnClickListener { + // Negating logic to sync with the switch component state allowDownloadAccess = !allowDownloadAccess binding.addProfileActivityAllowDownloadSwitch.isChecked = allowDownloadAccess } From b4b5f10711e634b9d21fed5f28f9ae3f0777dea1 Mon Sep 17 00:00:00 2001 From: XichengSpencer <74568012+XichengSpencer@users.noreply.github.com> Date: Tue, 19 Dec 2023 11:49:32 -0500 Subject: [PATCH 08/13] Add new HtmlParser create method that use less variables --- .../MathExpressionParserViewModel.kt | 5 +-- .../android/util/parser/html/HtmlParser.kt | 35 +++++++++++++++++-- 2 files changed, 33 insertions(+), 7 deletions(-) diff --git a/app/src/main/java/org/oppia/android/app/devoptions/mathexpressionparser/MathExpressionParserViewModel.kt b/app/src/main/java/org/oppia/android/app/devoptions/mathexpressionparser/MathExpressionParserViewModel.kt index e808c6fdb68..80dd8a16946 100644 --- a/app/src/main/java/org/oppia/android/app/devoptions/mathexpressionparser/MathExpressionParserViewModel.kt +++ b/app/src/main/java/org/oppia/android/app/devoptions/mathexpressionparser/MathExpressionParserViewModel.kt @@ -33,10 +33,7 @@ class MathExpressionParserViewModel @Inject constructor( private val htmlParser by lazy { // TODO(#4206): Replace this with the variant that doesn't require GCS properties. htmlParserFactory.create( - gcsResourceName = "", - entityType = "", - entityId = "", - imageCenterAlign = false, + customOppiaTagActionListener = null, displayLocale = appLanguageResourceHandler.getDisplayLocale() ) } diff --git a/utility/src/main/java/org/oppia/android/util/parser/html/HtmlParser.kt b/utility/src/main/java/org/oppia/android/util/parser/html/HtmlParser.kt index cb37742ff19..9cf4c1d105a 100755 --- a/utility/src/main/java/org/oppia/android/util/parser/html/HtmlParser.kt +++ b/utility/src/main/java/org/oppia/android/util/parser/html/HtmlParser.kt @@ -75,7 +75,6 @@ class HtmlParser private constructor( supportsLinks: Boolean = false, supportsConceptCards: Boolean = false ): Spannable { - var htmlContent = rawString // Canvas does not support RTL, it always starts from left to right in RTL due to which compound drawables are @@ -121,11 +120,17 @@ class HtmlParser private constructor( } val imageGetter = urlImageParserFactory?.create( - htmlContentTextView, gcsResourceName, entityType, entityId, imageCenterAlign + htmlContentTextView, + gcsResourceName, + entityType, + entityId, + imageCenterAlign ) val htmlSpannable = CustomHtmlContentHandler.fromHtml( - htmlContent, imageGetter, computeCustomTagHandlers(supportsConceptCards, htmlContentTextView) + htmlContent, + imageGetter, + computeCustomTagHandlers(supportsConceptCards, htmlContentTextView) ) return ensureNonEmpty(trimSpannable(htmlSpannable as SpannableStringBuilder)) @@ -227,6 +232,30 @@ class HtmlParser private constructor( ) } + /** + * Returns a new [HtmlParser] with the empty entity type and ID for loading images, + * doesn't require GCS properties and imageCenterAlign set to false + * optionally specified [CustomOppiaTagActionListener] for handling custom Oppia tag events. + */ + fun create( + customOppiaTagActionListener: CustomOppiaTagActionListener? = null, + displayLocale: OppiaLocale.DisplayLocale + ): HtmlParser { + return HtmlParser( + context, + urlImageParserFactory, + gcsResourceName = "", + entityType = "", + entityId = "", + imageCenterAlign = false, + consoleLogger, + cacheLatexRendering = enableCacheLatexRendering.value, + customOppiaTagActionListener, + null, + displayLocale + ) + } + /** * Returns a new [HtmlParser] with an optionally specified [CustomOppiaTagActionListener] and * [PolicyOppiaTagActionListener] for handling custom Oppia tag events. Note that Oppia image From 015b50276d5d24906d883f66969743fc82950c7a Mon Sep 17 00:00:00 2001 From: XichengSpencer <74568012+XichengSpencer@users.noreply.github.com> Date: Mon, 8 Jan 2024 12:01:15 -0500 Subject: [PATCH 09/13] Remove customOppiaTagActionListener as input arg in HtmlParser.kt create function that served for MathExpressionParserViewModel.kt --- .../mathexpressionparser/MathExpressionParserViewModel.kt | 1 - .../main/java/org/oppia/android/util/parser/html/HtmlParser.kt | 3 +-- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/app/src/main/java/org/oppia/android/app/devoptions/mathexpressionparser/MathExpressionParserViewModel.kt b/app/src/main/java/org/oppia/android/app/devoptions/mathexpressionparser/MathExpressionParserViewModel.kt index 80dd8a16946..f0e7a8c147e 100644 --- a/app/src/main/java/org/oppia/android/app/devoptions/mathexpressionparser/MathExpressionParserViewModel.kt +++ b/app/src/main/java/org/oppia/android/app/devoptions/mathexpressionparser/MathExpressionParserViewModel.kt @@ -33,7 +33,6 @@ class MathExpressionParserViewModel @Inject constructor( private val htmlParser by lazy { // TODO(#4206): Replace this with the variant that doesn't require GCS properties. htmlParserFactory.create( - customOppiaTagActionListener = null, displayLocale = appLanguageResourceHandler.getDisplayLocale() ) } diff --git a/utility/src/main/java/org/oppia/android/util/parser/html/HtmlParser.kt b/utility/src/main/java/org/oppia/android/util/parser/html/HtmlParser.kt index 120a545d193..59019d70c8d 100755 --- a/utility/src/main/java/org/oppia/android/util/parser/html/HtmlParser.kt +++ b/utility/src/main/java/org/oppia/android/util/parser/html/HtmlParser.kt @@ -251,7 +251,6 @@ class HtmlParser private constructor( * optionally specified [CustomOppiaTagActionListener] for handling custom Oppia tag events. */ fun create( - customOppiaTagActionListener: CustomOppiaTagActionListener? = null, displayLocale: OppiaLocale.DisplayLocale ): HtmlParser { return HtmlParser( @@ -263,7 +262,7 @@ class HtmlParser private constructor( imageCenterAlign = false, consoleLogger, cacheLatexRendering = enableCacheLatexRendering.value, - customOppiaTagActionListener, + customOppiaTagActionListener = null, null, displayLocale ) From 74b599cb8f2467a67fa897ad43b2f371e4d6be08 Mon Sep 17 00:00:00 2001 From: XichengSpencer <74568012+XichengSpencer@users.noreply.github.com> Date: Tue, 16 Jan 2024 11:58:39 -0500 Subject: [PATCH 10/13] Remove TODO list and updated unnamed variable in both create function --- .../mathexpressionparser/MathExpressionParserViewModel.kt | 1 - .../java/org/oppia/android/util/parser/html/HtmlParser.kt | 4 ++-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/org/oppia/android/app/devoptions/mathexpressionparser/MathExpressionParserViewModel.kt b/app/src/main/java/org/oppia/android/app/devoptions/mathexpressionparser/MathExpressionParserViewModel.kt index f0e7a8c147e..95fb16f7a05 100644 --- a/app/src/main/java/org/oppia/android/app/devoptions/mathexpressionparser/MathExpressionParserViewModel.kt +++ b/app/src/main/java/org/oppia/android/app/devoptions/mathexpressionparser/MathExpressionParserViewModel.kt @@ -31,7 +31,6 @@ class MathExpressionParserViewModel @Inject constructor( private val htmlParserFactory: HtmlParser.Factory ) : ObservableViewModel() { private val htmlParser by lazy { - // TODO(#4206): Replace this with the variant that doesn't require GCS properties. htmlParserFactory.create( displayLocale = appLanguageResourceHandler.getDisplayLocale() ) diff --git a/utility/src/main/java/org/oppia/android/util/parser/html/HtmlParser.kt b/utility/src/main/java/org/oppia/android/util/parser/html/HtmlParser.kt index 59019d70c8d..534772b6d14 100755 --- a/utility/src/main/java/org/oppia/android/util/parser/html/HtmlParser.kt +++ b/utility/src/main/java/org/oppia/android/util/parser/html/HtmlParser.kt @@ -240,7 +240,7 @@ class HtmlParser private constructor( consoleLogger, cacheLatexRendering = enableCacheLatexRendering.value, customOppiaTagActionListener, - null, + policyOppiaTagActionListener = null, displayLocale ) } @@ -263,7 +263,7 @@ class HtmlParser private constructor( consoleLogger, cacheLatexRendering = enableCacheLatexRendering.value, customOppiaTagActionListener = null, - null, + policyOppiaTagActionListener = null, displayLocale ) } From 2fc2da86111ba9a22b08a8706d8cb46a84ec569a Mon Sep 17 00:00:00 2001 From: XichengSpencer <74568012+XichengSpencer@users.noreply.github.com> Date: Wed, 17 Jan 2024 15:10:07 -0500 Subject: [PATCH 11/13] Fix all unnamed variables --- .../android/util/parser/html/HtmlParser.kt | 26 +++++++++---------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/utility/src/main/java/org/oppia/android/util/parser/html/HtmlParser.kt b/utility/src/main/java/org/oppia/android/util/parser/html/HtmlParser.kt index 534772b6d14..f08fcfe807a 100755 --- a/utility/src/main/java/org/oppia/android/util/parser/html/HtmlParser.kt +++ b/utility/src/main/java/org/oppia/android/util/parser/html/HtmlParser.kt @@ -231,17 +231,17 @@ class HtmlParser private constructor( displayLocale: OppiaLocale.DisplayLocale ): HtmlParser { return HtmlParser( - context, - urlImageParserFactory, - gcsResourceName, - entityType, - entityId, - imageCenterAlign, - consoleLogger, + context = context, + urlImageParserFactory = urlImageParserFactory, + gcsResourceName = gcsResourceName, + entityType = entityType, + entityId = entityId, + imageCenterAlign = imageCenterAlign, + consoleLogger = consoleLogger, cacheLatexRendering = enableCacheLatexRendering.value, - customOppiaTagActionListener, + customOppiaTagActionListener = customOppiaTagActionListener, policyOppiaTagActionListener = null, - displayLocale + displayLocale = displayLocale ) } @@ -254,17 +254,17 @@ class HtmlParser private constructor( displayLocale: OppiaLocale.DisplayLocale ): HtmlParser { return HtmlParser( - context, - urlImageParserFactory, + context = context, + urlImageParserFactory = urlImageParserFactory, gcsResourceName = "", entityType = "", entityId = "", imageCenterAlign = false, - consoleLogger, + consoleLogger = consoleLogger, cacheLatexRendering = enableCacheLatexRendering.value, customOppiaTagActionListener = null, policyOppiaTagActionListener = null, - displayLocale + displayLocale = displayLocale ) } From 0c1b62a1480cdd4970031697f9030affe191f01d Mon Sep 17 00:00:00 2001 From: XichengSpencer <74568012+XichengSpencer@users.noreply.github.com> Date: Fri, 23 Feb 2024 14:54:39 -0500 Subject: [PATCH 12/13] Add annotation for methods not compatible with = withColorBackgroundMatching( descriptionSuffix = "an opaque background" ) { color -> color?.extractAlpha() == 0xff } @@ -27,6 +30,7 @@ class GenericViewMatchers { * Returns a [Matcher] with the specified description suffix and color matcher, matching against * filled background colors of views. */ + @RequiresApi(Build.VERSION_CODES.N) private fun withColorBackgroundMatching( @Suppress("SameParameterValue") descriptionSuffix: String, colorMatcher: (Long?) -> Boolean diff --git a/testing/src/main/java/org/oppia/android/testing/junit/OppiaParameterizedTestRunner.kt b/testing/src/main/java/org/oppia/android/testing/junit/OppiaParameterizedTestRunner.kt index 4dd7b3427c7..512d4bf4a65 100644 --- a/testing/src/main/java/org/oppia/android/testing/junit/OppiaParameterizedTestRunner.kt +++ b/testing/src/main/java/org/oppia/android/testing/junit/OppiaParameterizedTestRunner.kt @@ -1,5 +1,7 @@ package org.oppia.android.testing.junit +import android.os.Build +import androidx.annotation.RequiresApi import org.junit.runner.Description import org.junit.runner.Runner import org.junit.runner.manipulation.Filter @@ -76,6 +78,7 @@ import kotlin.reflect.KClass * contain (thus they should be treated as undefined outside of tests that specific define their * value via [Iteration]). */ +@RequiresApi(Build.VERSION_CODES.N) class OppiaParameterizedTestRunner(private val testClass: Class<*>) : Suite(testClass, listOf()) { private val parameterizedMethods = computeParameterizedMethods() private val selectedRunnerClass by lazy { fetchSelectedRunnerPlatformClass() } @@ -85,16 +88,24 @@ class OppiaParameterizedTestRunner(private val testClass: Class<*>) : Suite(test parameterizedMethods.flatMap { (methodName, method) -> method.iterationNames.map { iterationName -> ProxyParameterizedTestRunner( - selectedRunnerClass, testClass, parameterizedMethods, methodName, iterationName + selectedRunnerClass, + testClass, + parameterizedMethods, + methodName, + iterationName ) } } + ProxyParameterizedTestRunner( - selectedRunnerClass, testClass, parameterizedMethods, methodName = null + selectedRunnerClass, + testClass, + parameterizedMethods, + methodName = null ) } override fun getChildren(): MutableList = childrenRunners.toMutableList() + @RequiresApi(Build.VERSION_CODES.N) private fun computeParameterizedMethods(): Map { val fieldsAndParsers = fetchParameterizedFields().map { field -> val valueParser = ParameterValue.createParserForField(field) @@ -184,12 +195,14 @@ class OppiaParameterizedTestRunner(private val testClass: Class<*>) : Suite(test }.associateBy { it.methodName } } + @RequiresApi(Build.VERSION_CODES.N) private fun fetchParameterizedFields(): List { return testClass.declaredFields.mapNotNull { field -> field.getDeclaredAnnotation(Parameter::class.java)?.let { field } } } + @RequiresApi(Build.VERSION_CODES.N) private fun fetchParameterizedMethodDeclarations(): List { return testClass.declaredMethods.mapNotNull { method -> method.getDeclaredAnnotationsByType(Iteration::class.java).map { parameters -> @@ -208,6 +221,7 @@ class OppiaParameterizedTestRunner(private val testClass: Class<*>) : Suite(test } } + @RequiresApi(Build.VERSION_CODES.N) private fun fetchSelectedRunnerPlatformClass(): Class<*> { return checkNotNull(testClass.getDeclaredAnnotation(SelectRunnerPlatform::class.java)) { "All suites using OppiaParameterizedTestRunner must declare their base platform runner" + @@ -239,7 +253,8 @@ class OppiaParameterizedTestRunner(private val testClass: Class<*>) : Suite(test * - [Float]s * - [Double]s */ - @Target(AnnotationTarget.FIELD) annotation class Parameter + @Target(AnnotationTarget.FIELD) + annotation class Parameter /** * Specifies that a method in a test that uses a [OppiaParameterizedTestRunner] runner should be @@ -247,7 +262,8 @@ class OppiaParameterizedTestRunner(private val testClass: Class<*>) : Suite(test * * See the KDoc for the runner for example code. */ - @Target(AnnotationTarget.FUNCTION) annotation class RunParameterized(vararg val value: Iteration) + @Target(AnnotationTarget.FUNCTION) + annotation class RunParameterized(vararg val value: Iteration) // TODO(#4120): Migrate to Kotlin @Repeatable once Kotlin 1.6 is used (see: // https://youtrack.jetbrains.com/issue/KT-12794). @@ -300,7 +316,10 @@ class OppiaParameterizedTestRunner(private val testClass: Class<*>) : Suite(test private fun constructDelegate(): Any { val constructor = runnerClass.getConstructor( - Class::class.java, Map::class.java, String::class.java, String::class.java + Class::class.java, + Map::class.java, + String::class.java, + String::class.java ) return constructor.newInstance(testClass, parameterizedMethods, methodName, iterationName) } diff --git a/testing/src/main/java/org/oppia/android/testing/threading/TestCoroutineDispatchersRobolectricImpl.kt b/testing/src/main/java/org/oppia/android/testing/threading/TestCoroutineDispatchersRobolectricImpl.kt index 3c93d9065bd..2f27175670b 100644 --- a/testing/src/main/java/org/oppia/android/testing/threading/TestCoroutineDispatchersRobolectricImpl.kt +++ b/testing/src/main/java/org/oppia/android/testing/threading/TestCoroutineDispatchersRobolectricImpl.kt @@ -1,5 +1,7 @@ package org.oppia.android.testing.threading +import android.os.Build +import androidx.annotation.RequiresApi import org.oppia.android.testing.time.FakeSystemClock import java.lang.reflect.Method import java.time.Duration @@ -34,6 +36,7 @@ class TestCoroutineDispatchersRobolectricImpl @Inject constructor( } while (hasPendingCompletableTasks()) } + @RequiresApi(Build.VERSION_CODES.O) override fun advanceTimeBy(delayTimeMillis: Long) { var remainingDelayMillis = delayTimeMillis while (remainingDelayMillis > 0) { @@ -49,6 +52,7 @@ class TestCoroutineDispatchersRobolectricImpl @Inject constructor( } } + @RequiresApi(Build.VERSION_CODES.O) override fun advanceUntilIdle() { // First, run through all tasks that are currently pending and can be run immediately. runCurrent() @@ -67,6 +71,7 @@ class TestCoroutineDispatchersRobolectricImpl @Inject constructor( } } + @RequiresApi(Build.VERSION_CODES.O) private fun advanceToNextFutureTask( currentTimeMillis: Long, maxDelayMs: Long = Long.MAX_VALUE @@ -94,6 +99,7 @@ class TestCoroutineDispatchersRobolectricImpl @Inject constructor( } /** Returns whether any of the dispatchers have any tasks to run, including in the future. */ + @RequiresApi(Build.VERSION_CODES.O) private fun hasPendingTasks(): Boolean { return backgroundTestDispatcher.hasPendingTasks() || blockingTestDispatcher.hasPendingTasks() || @@ -107,6 +113,7 @@ class TestCoroutineDispatchersRobolectricImpl @Inject constructor( !uiTaskCoordinator.isIdle() } + @RequiresApi(Build.VERSION_CODES.O) private fun getNextFutureTaskTimeMillis(timeMillis: Long): Long? { val nextBackgroundFutureTaskTimeMills = backgroundTestDispatcher.getNextFutureTaskCompletionTimeMillis(timeMillis) @@ -120,6 +127,7 @@ class TestCoroutineDispatchersRobolectricImpl @Inject constructor( return futureTimes.firstOrNull() } + @RequiresApi(Build.VERSION_CODES.O) private fun getNextUiThreadFutureTaskTimeMillis(timeMillis: Long): Long? { return uiTaskCoordinator.getNextUiThreadFutureTaskTimeMillis(timeMillis) } @@ -139,6 +147,7 @@ class TestCoroutineDispatchersRobolectricImpl @Inject constructor( idleMethod.invoke(shadowUiLooper) } + @RequiresApi(Build.VERSION_CODES.O) fun getNextUiThreadFutureTaskTimeMillis(timeMillis: Long): Long? { val nextScheduledTime = nextScheduledTimeMethod.invoke(shadowUiLooper) as Duration val delayMs = nextScheduledTime.toMillis() From e2c9ca44b5ec5a393352cddb3ce76417e108a142 Mon Sep 17 00:00:00 2001 From: XichengSpencer <74568012+XichengSpencer@users.noreply.github.com> Date: Tue, 26 Mar 2024 10:19:04 -0400 Subject: [PATCH 13/13] Revert "Add annotation for methods not compatible with ) : Suite(test parameterizedMethods.flatMap { (methodName, method) -> method.iterationNames.map { iterationName -> ProxyParameterizedTestRunner( - selectedRunnerClass, - testClass, - parameterizedMethods, - methodName, - iterationName + selectedRunnerClass, testClass, parameterizedMethods, methodName, iterationName ) } } + ProxyParameterizedTestRunner( - selectedRunnerClass, - testClass, - parameterizedMethods, - methodName = null + selectedRunnerClass, testClass, parameterizedMethods, methodName = null ) } @@ -253,8 +246,7 @@ class OppiaParameterizedTestRunner(private val testClass: Class<*>) : Suite(test * - [Float]s * - [Double]s */ - @Target(AnnotationTarget.FIELD) - annotation class Parameter + @Target(AnnotationTarget.FIELD) annotation class Parameter /** * Specifies that a method in a test that uses a [OppiaParameterizedTestRunner] runner should be @@ -262,8 +254,7 @@ class OppiaParameterizedTestRunner(private val testClass: Class<*>) : Suite(test * * See the KDoc for the runner for example code. */ - @Target(AnnotationTarget.FUNCTION) - annotation class RunParameterized(vararg val value: Iteration) + @Target(AnnotationTarget.FUNCTION) annotation class RunParameterized(vararg val value: Iteration) // TODO(#4120): Migrate to Kotlin @Repeatable once Kotlin 1.6 is used (see: // https://youtrack.jetbrains.com/issue/KT-12794). @@ -316,10 +307,7 @@ class OppiaParameterizedTestRunner(private val testClass: Class<*>) : Suite(test private fun constructDelegate(): Any { val constructor = runnerClass.getConstructor( - Class::class.java, - Map::class.java, - String::class.java, - String::class.java + Class::class.java, Map::class.java, String::class.java, String::class.java ) return constructor.newInstance(testClass, parameterizedMethods, methodName, iterationName) }