Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
105 changes: 82 additions & 23 deletions AnkiDroid/src/test/java/com/ichi2/anki/DeckPickerTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,12 @@ class DeckPickerTest : RobolectricTest() {
// but Android lifecycle callback (onCreate) have not yet executed.
DeckPicker()

assertDoesNotThrow { ChangeManager.notifySubscribers(opChanges { studyQueues = true }, null) }
assertDoesNotThrow {
ChangeManager.notifySubscribers(
opChanges { studyQueues = true },
null,
)
}
Comment on lines +100 to +105
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems to be a no-op

}

@Test
Expand Down Expand Up @@ -143,7 +148,8 @@ class DeckPickerTest : RobolectricTest() {
whenever(editor.remove(DeckPickerViewModel.UPGRADE_VERSION_KEY)).thenReturn(updated)
ActivityScenario.launch(DeckPicker::class.java).use { scenario ->
scenario.onActivity { deckPicker: DeckPicker ->
val previousVersion = deckPicker.viewModel.getPreviousVersion(preferences, newVersion)
val previousVersion =
deckPicker.viewModel.getPreviousVersion(preferences, newVersion)
assertEquals(40, previousVersion)
}
}
Expand All @@ -167,7 +173,8 @@ class DeckPickerTest : RobolectricTest() {
whenever(editor.remove(DeckPickerViewModel.UPGRADE_VERSION_KEY)).thenReturn(updated)
ActivityScenario.launch(DeckPicker::class.java).use { scenario ->
scenario.onActivity { deckPicker: DeckPicker ->
val previousVersion = deckPicker.viewModel.getPreviousVersion(preferences, newVersion)
val previousVersion =
deckPicker.viewModel.getPreviousVersion(preferences, newVersion)
assertEquals(prevVersion.toLong(), previousVersion)
}
}
Expand All @@ -186,7 +193,8 @@ class DeckPickerTest : RobolectricTest() {
whenever(preferences.edit()).thenReturn(editor)
ActivityScenario.launch(DeckPicker::class.java).use { scenario ->
scenario.onActivity { deckPicker: DeckPicker ->
val previousVersion = deckPicker.viewModel.getPreviousVersion(preferences, newVersion)
val previousVersion =
deckPicker.viewModel.getPreviousVersion(preferences, newVersion)
assertEquals(prevVersion, previousVersion)
}
}
Expand Down Expand Up @@ -377,15 +385,24 @@ class DeckPickerTest : RobolectricTest() {
deckPicker {
val didA = addDeck("Deck 1")

supportFragmentManager.selectContextMenuOption(DeckPickerContextMenuOption.RENAME_DECK, didA)
supportFragmentManager.selectContextMenuOption(
DeckPickerContextMenuOption.RENAME_DECK,
didA,
)
assertDialogTitleEquals("Rename deck")
dismissAllDialogFragments()

supportFragmentManager.selectContextMenuOption(DeckPickerContextMenuOption.CREATE_SUBDECK, didA)
supportFragmentManager.selectContextMenuOption(
DeckPickerContextMenuOption.CREATE_SUBDECK,
didA,
)
assertDialogTitleEquals("Create subdeck")
dismissAllDialogFragments()

supportFragmentManager.selectContextMenuOption(DeckPickerContextMenuOption.CUSTOM_STUDY, didA)
supportFragmentManager.selectContextMenuOption(
DeckPickerContextMenuOption.CUSTOM_STUDY,
didA,
)
assertDialogTitleEquals("Custom study")
dismissAllDialogFragments()

Expand Down Expand Up @@ -432,48 +449,80 @@ class DeckPickerTest : RobolectricTest() {
val didA = addDeck("Deck 1")
val didDynamicA = addDynamicDeck("Deck Dynamic 1")

val noteEditor = selectContextMenuOptionForActivity(DeckPickerContextMenuOption.ADD_CARD, didA)
val noteEditor =
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please revert all these spacing changes, they make it difficult to understand the change

selectContextMenuOptionForActivity(DeckPickerContextMenuOption.ADD_CARD, didA)
assertEquals("com.ichi2.anki.NoteEditorActivity", noteEditor.component!!.className)
onBackPressedDispatcher.onBackPressed()

val browser = selectContextMenuOptionForActivity(DeckPickerContextMenuOption.BROWSE_CARDS, didA)
val browser =
selectContextMenuOptionForActivity(DeckPickerContextMenuOption.BROWSE_CARDS, didA)
assertEquals("com.ichi2.anki.CardBrowser", browser.component!!.className)
onBackPressedDispatcher.onBackPressed()

// select deck options for a normal deck
val deckOptionsNormal = selectContextMenuOptionForActivity(DeckPickerContextMenuOption.DECK_OPTIONS, didA)
assertEquals("com.ichi2.anki.SingleFragmentActivity", deckOptionsNormal.component!!.className)
val deckOptionsNormal =
selectContextMenuOptionForActivity(DeckPickerContextMenuOption.DECK_OPTIONS, didA)
assertEquals(
"com.ichi2.anki.SingleFragmentActivity",
deckOptionsNormal.component!!.className,
)
onBackPressedDispatcher.onBackPressed()

// select deck options for a dynamic deck
val deckOptionsDynamic = selectContextMenuOptionForActivity(DeckPickerContextMenuOption.DECK_OPTIONS, didDynamicA)
assertEquals("com.ichi2.anki.FilteredDeckOptions", deckOptionsDynamic.component!!.className)
val deckOptionsDynamic =
selectContextMenuOptionForActivity(
DeckPickerContextMenuOption.DECK_OPTIONS,
didDynamicA,
)
assertEquals(
"com.ichi2.anki.FilteredDeckOptions",
deckOptionsDynamic.component!!.className,
)
onBackPressedDispatcher.onBackPressed()

Prefs.newReviewRemindersEnabled = true
val scheduleReminders = selectContextMenuOptionForActivity(DeckPickerContextMenuOption.SCHEDULE_REMINDERS, didA)
assertEquals("com.ichi2.anki.SingleFragmentActivity", scheduleReminders.component!!.className)
val scheduleReminders =
selectContextMenuOptionForActivity(
DeckPickerContextMenuOption.SCHEDULE_REMINDERS,
didA,
)
assertEquals(
"com.ichi2.anki.SingleFragmentActivity",
scheduleReminders.component!!.className,
)
onBackPressedDispatcher.onBackPressed()
}

@Test
fun `ContextMenu deletes deck when selecting DELETE_DECK`() =
deckPicker {
val didA = addDeck("Deck 1")
supportFragmentManager.selectContextMenuOption(DeckPickerContextMenuOption.DELETE_DECK, didA)
assertThat(getColUnsafe.decks.allNamesAndIds().map { it.id }, not(containsInAnyOrder(didA)))
supportFragmentManager.selectContextMenuOption(
DeckPickerContextMenuOption.DELETE_DECK,
didA,
)
assertThat(
getColUnsafe.decks.allNamesAndIds().map { it.id },
not(containsInAnyOrder(didA)),
)
}

@Test
fun `ContextMenu creates deck shortcut when selecting CREATE_SHORTCUT`() =
deckPicker {
val didA = addDeck("Deck 1")
supportFragmentManager.selectContextMenuOption(DeckPickerContextMenuOption.CREATE_SHORTCUT, didA)
supportFragmentManager.selectContextMenuOption(
DeckPickerContextMenuOption.CREATE_SHORTCUT,
didA,
)
// Wait for the shortcut creation to complete
ShadowLooper.runUiThreadTasksIncludingDelayedTasks()
assertEquals(
"Deck 1",
ShortcutManagerCompat.getShortcuts(this, ShortcutManagerCompat.FLAG_MATCH_PINNED).first().shortLabel,
ShortcutManagerCompat
.getShortcuts(this, ShortcutManagerCompat.FLAG_MATCH_PINNED)
.first()
.shortLabel,
)
}

Expand All @@ -493,7 +542,10 @@ class DeckPickerTest : RobolectricTest() {
advanceRobolectricLooper()
assertEquals(1, visibleDeckCount)
assertTrue(getColUnsafe.sched.haveBuried(), "Deck should have buried cards")
supportFragmentManager.selectContextMenuOption(DeckPickerContextMenuOption.UNBURY, deckId)
supportFragmentManager.selectContextMenuOption(
DeckPickerContextMenuOption.UNBURY,
deckId,
)
kotlin.test.assertFalse(getColUnsafe.sched.haveBuried())
}

Expand All @@ -508,14 +560,21 @@ class DeckPickerTest : RobolectricTest() {
getColUnsafe.sched.rebuildFilteredDeck(deckId)
assertTrue(allCardsInSameDeck(cardIds, deckId))
updateDeckList()
advanceRobolectricLooper()
assertEquals(1, visibleDeckCount)

supportFragmentManager.selectContextMenuOption(DeckPickerContextMenuOption.CUSTOM_STUDY_EMPTY, deckId) // Empty
supportFragmentManager.selectContextMenuOption(
DeckPickerContextMenuOption.CUSTOM_STUDY_EMPTY,
deckId,
) // Empty

assertTrue(allCardsInSameDeck(cardIds, 1))

supportFragmentManager.selectContextMenuOption(DeckPickerContextMenuOption.CUSTOM_STUDY_REBUILD, deckId) // Rebuild

supportFragmentManager.selectContextMenuOption(
DeckPickerContextMenuOption.CUSTOM_STUDY_REBUILD,
deckId,
) // Rebuild
advanceRobolectricLooper()
assertTrue(allCardsInSameDeck(cardIds, deckId))
}

Expand Down
25 changes: 13 additions & 12 deletions AnkiDroid/src/test/java/com/ichi2/anki/ReviewerTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ import org.junit.Ignore
import org.junit.Test
import org.junit.runner.RunWith
import org.robolectric.Shadows
import org.robolectric.shadows.ShadowLooper.runUiThreadTasksIncludingDelayedTasks
import timber.log.Timber
import kotlin.test.junit5.JUnit5Asserter.assertNotNull

Expand Down Expand Up @@ -246,31 +247,27 @@ class ReviewerTest : RobolectricTest() {
addBasicNote("2", "bar").firstCard(),
addBasicNote("3", "bar").firstCard(),
)
advanceRobolectricLooper()

val reviewer = startReviewer()

advanceRobolectricLooper()

equalFirstField(cards[0], reviewer.currentCard!!)
reviewer.answerCard(Rating.AGAIN)
advanceRobolectricLooper()
runUiThreadTasksIncludingDelayedTasks()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These appear to be equivalent

        fun advanceRobolectricLooper() {
            Shadows.shadowOf(Looper.getMainLooper()).runToEndOfTasks()
        }
  public static void runUiThreadTasksIncludingDelayedTasks() {
    getShadowMainLooper().runToEndOfTasks();
  }


equalFirstField(cards[1], reviewer.currentCard!!)
reviewer.answerCard(Rating.AGAIN)
advanceRobolectricLooper()
runUiThreadTasksIncludingDelayedTasks()

undo(reviewer)
advanceRobolectricLooper()

equalFirstField(cards[1], reviewer.currentCard!!)
reviewer.answerCard(Rating.GOOD)
advanceRobolectricLooper()
runUiThreadTasksIncludingDelayedTasks()

equalFirstField(cards[2], reviewer.currentCard!!)
time.addM(2)
reviewer.answerCard(Rating.GOOD)
advanceRobolectricLooper()
runUiThreadTasksIncludingDelayedTasks()

equalFirstField(
cards[0],
reviewer.currentCard!!,
Expand Down Expand Up @@ -359,14 +356,17 @@ class ReviewerTest : RobolectricTest() {
val nonDefaultDeck = addDeck("Hello")
assertThat("first card is shown", this.cardContent, containsString("One"))
flipOrAnswerCard(Rating.GOOD)
advanceRobolectricLooper()
// answer good, 'Rating.GOOD' should now be < 10m
assertThat("initial time is 10m", this.getCardDataForJsApi().nextTime3, equalTo("<\u206810\u2069m"))
flipOrAnswerCard(Rating.GOOD)
advanceRobolectricLooper()
assertThat("next card is shown", this.cardContent, containsString("Two"))

undoableOp { col.setDeck(listOf(currentCard!!.id), nonDefaultDeck) }

advanceRobolectricLooper()
flipOrAnswerCard(Rating.GOOD)
advanceRobolectricLooper()
assertThat("buttons should be updated", this.getCardDataForJsApi().nextTime3, equalTo("\u20681\u2069d"))
assertThat("content should be updated", this.cardContent, containsString("One"))
}
Expand Down Expand Up @@ -403,6 +403,7 @@ class ReviewerTest : RobolectricTest() {

private fun undo(reviewer: Reviewer) {
reviewer.undo()
runUiThreadTasksIncludingDelayedTasks()
}

@Suppress("SameParameterValue")
Expand Down Expand Up @@ -439,14 +440,14 @@ class ReviewerTest : RobolectricTest() {

r.answerCard(Rating.GOOD)

advanceRobolectricLooper()
runUiThreadTasksIncludingDelayedTasks()
}

private fun assertCurrentOrdIs(
r: Reviewer,
i: Int,
) {
advanceRobolectricLooper()
runUiThreadTasksIncludingDelayedTasks()
val ord = r.currentCard!!.ord

assertThat("Unexpected card ord", ord + 1, equalTo(i))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,10 +59,10 @@ class PrefsSearchBarTest : RobolectricTest() {

// Join both lists
val allResIds =
filesResIds
.plus(prefItemsResIds)
.distinct() as List<Int>

(filesResIds + prefItemsResIds)
.filterIsInstance<Int>()
.filter { it != 0 }
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is there sometimes a resource of 0?

It's best to figure this out, rather than ignore something in the test which we don't understand.

Is this 0 a missing resource, or something which was incorrectly loaded?

I think the best option would be to add a log of the count + names of all selected resource IDs, then we know if it's extra or missing.

.distinct()
// Check if all indexed XML resIDs lead to the correct fragments on getFragmentFromXmlRes
for (resId in allResIds) {
val fragment = getFragmentFromXmlRes(resId)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import java.util.Calendar
import java.util.TimeZone
import kotlin.time.Duration.Companion.minutes

@RunWith(AndroidJUnit4::class)
Expand All @@ -60,6 +61,7 @@ class AlarmManagerServiceTest : RobolectricTest() {
@Before
override fun setUp() {
super.setUp()
TimeZone.setDefault(TimeZone.getTimeZone("UTC"))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Won't this fail at the same time in UTC?

context = mockk(relaxed = true)
alarmManager = mockk(relaxed = true)
notificationManager = mockk(relaxed = true)
Expand Down
8 changes: 5 additions & 3 deletions common/src/main/java/com/ichi2/anki/common/time/MockTime.kt
Original file line number Diff line number Diff line change
Expand Up @@ -102,9 +102,11 @@ open class MockTime(
milliseconds: Int = 0,
): Long {
val timeZone = TimeZone.getTimeZone("GMT")
val gregorianCalendar: Calendar = GregorianCalendar(year, month, date, hourOfDay, minute, second)
gregorianCalendar.timeZone = timeZone
gregorianCalendar[Calendar.MILLISECOND] = milliseconds
val gregorianCalendar: Calendar =
GregorianCalendar(timeZone).apply {
set(year, month, date, hourOfDay, minute, second)
set(Calendar.MILLISECOND, milliseconds)
}
return gregorianCalendar.timeInMillis
}
}
Expand Down
Loading