From 6c3c9801c6686a64a2b13df02fa7543e34f7653b Mon Sep 17 00:00:00 2001 From: Mateusz Budnik Date: Wed, 8 Nov 2023 22:07:23 +0100 Subject: [PATCH] [#7] Add unit tests to CalendarViewModel --- .github/workflows/gradle.yml | 9 +- app/build.gradle | 2 +- gradlew | 174 +++++++++--------- library/build.gradle | 17 +- .../mabn/calendarlibrary/CalendarViewModel.kt | 35 ++-- .../component/CalendarPager.kt | 17 +- .../component/InlineCalendar.kt | 3 +- .../component/MonthViewCalendar.kt | 7 +- .../calendarlibrary/core/CalendarIntent.kt | 4 +- .../calendarlibrary/core/DateTimeConstants.kt | 7 + .../calendarlibrary/core/TimePeriodType.kt | 7 + .../calendarlibrary/CalendarViewModelTest.kt | 85 +++++++++ .../calendarlibrary/LocalDateExtensionTest.kt | 22 +-- 13 files changed, 249 insertions(+), 140 deletions(-) create mode 100644 library/src/main/java/com/mabn/calendarlibrary/core/DateTimeConstants.kt create mode 100644 library/src/main/java/com/mabn/calendarlibrary/core/TimePeriodType.kt create mode 100644 library/src/test/java/com/mabn/calendarlibrary/CalendarViewModelTest.kt diff --git a/.github/workflows/gradle.yml b/.github/workflows/gradle.yml index 313dc83..5169d94 100644 --- a/.github/workflows/gradle.yml +++ b/.github/workflows/gradle.yml @@ -18,17 +18,14 @@ permissions: jobs: build: - runs-on: ubuntu-latest - steps: - uses: actions/checkout@v3 - - name: Set up JDK 11 + - name: Set up JDK 18 uses: actions/setup-java@v3 with: - java-version: '11' + java-version: '18' distribution: 'temurin' - name: Build with Gradle uses: gradle/gradle-build-action@67421db6bd0bf253fb4bd25b31ebb98943c375e1 - with: - arguments: build + run: ./gradlew build --stacktrace diff --git a/app/build.gradle b/app/build.gradle index c1d4a67..d6abcc9 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -53,7 +53,7 @@ dependencies { implementation "androidx.compose.material:material:$compose_version" implementation "androidx.compose.ui:ui-tooling-preview:$compose_version" implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.6.2' - implementation 'androidx.activity:activity-compose:1.8.0' + implementation 'androidx.activity:activity-compose:1.8.1' testImplementation 'junit:junit:4.13.2' androidTestImplementation 'androidx.test.ext:junit:1.1.5' androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1' diff --git a/gradlew b/gradlew index 62f4417..d71de43 100755 --- a/gradlew +++ b/gradlew @@ -27,20 +27,20 @@ PRG="$0" # Need this for relative symlinks. while [ -h "$PRG" ] ; do - ls=`ls -ld "$PRG"` - link=`expr "$ls" : '.*-> \(.*\)$'` - if expr "$link" : '/.*' > /dev/null; then - PRG="$link";; - else - PRG=`dirname "$PRG"`"/$link" - fi -done +ls=`ls -ld "$PRG"` +link=`expr "$ls" : '.*-> \(.*\)$'` +if expr "$link" : '/.*' > /dev/null; then + PRG="$link" +else +PRG=`dirname "$PRG"`"/$link" +fi + done SAVED="`pwd`" cd "`dirname \"$PRG\"`/" >/dev/null -APP_HOME="`pwd -P`" + APP_HOME="`pwd -P`" cd "$SAVED" >/dev/null -APP_NAME="Gradle" + APP_NAME="Gradle" APP_BASE_NAME=`basename "$0"` # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. @@ -66,111 +66,111 @@ msys=false darwin=false nonstop=false case "`uname`" in - CYGWIN* ) - cygwin=true - ;; - Darwin* ) - darwin=true - ;; - MINGW* ) - msys=true - ;; - NONSTOP* ) - nonstop=true - ;; + CYGWIN* ) +cygwin=true +;; +Darwin* ) +darwin=true +;; +MINGW* ) +msys=true +;; +NONSTOP* ) +nonstop=true +;; esac -CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar # Determine the Java command to use to start the JVM. if [ -n "$JAVA_HOME" ] ; then - if [ -x "$JAVA_HOME/jre/sh/java" ] ; then - # IBM's JDK on AIX uses strange locations for the executables +if [ -x "$JAVA_HOME/jre/sh/java" ] ; then +# IBM's JDK on AIX uses strange locations for the executables JAVACMD="$JAVA_HOME/jre/sh/java" - else - JAVACMD="$JAVA_HOME/bin/java" - fi - if [ ! -x "$JAVACMD" ] ; then +else +JAVACMD="$JAVA_HOME/bin/java" +fi +if [ ! -x "$JAVACMD" ] ; then die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME Please set the JAVA_HOME variable in your environment to match the -location of your Java installation." - fi + location of your Java installation." +fi else - JAVACMD="java" - which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +JAVACMD="java" +which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the -location of your Java installation." + location of your Java installation." fi # Increase the maximum file descriptors if we can. if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then - MAX_FD_LIMIT=`ulimit -H -n` - if [ $? -eq 0 ] ; then - if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then - MAX_FD="$MAX_FD_LIMIT" - fi + MAX_FD_LIMIT=`ulimit -H -n` +if [ $? -eq 0 ] ; then +if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then + MAX_FD="$MAX_FD_LIMIT" +fi ulimit -n $MAX_FD - if [ $? -ne 0 ] ; then - warn "Could not set maximum file descriptor limit: $MAX_FD" - fi - else - warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" - fi +if [ $? -ne 0 ] ; then + warn "Could not set maximum file descriptor limit: $MAX_FD" fi +else +warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" +fi + fi # For Darwin, add options to specify how the application appears in the dock if $darwin; then - GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" + GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" fi # For Cygwin or MSYS, switch paths to Windows format before running java if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then - APP_HOME=`cygpath --path --mixed "$APP_HOME"` - CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` - - JAVACMD=`cygpath --unix "$JAVACMD"` - - # We build the pattern for arguments to be converted via cygpath - ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` - SEP="" - for dir in $ROOTDIRSRAW ; do - ROOTDIRS="$ROOTDIRS$SEP$dir" - SEP="|" - done - OURCYGPATTERN="(^($ROOTDIRS))" - # Add a user-defined pattern to the cygpath arguments - if [ "$GRADLE_CYGPATTERN" != "" ] ; then + APP_HOME=`cygpath --path --mixed "$APP_HOME"` +CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + +JAVACMD=`cygpath --unix "$JAVACMD"` + +# We build the pattern for arguments to be converted via cygpath +ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` +SEP="" +for dir in $ROOTDIRSRAW ; do +ROOTDIRS="$ROOTDIRS$SEP$dir" +SEP="|" +done + OURCYGPATTERN="(^($ROOTDIRS))" +# Add a user-defined pattern to the cygpath arguments +if [ "$GRADLE_CYGPATTERN" != "" ] ; then OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" - fi - # Now convert the arguments - kludge to limit ourselves to /bin/sh - i=0 - for arg in "$@" ; do - CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` - CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option - - if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition - eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` - else - eval `echo args$i`="\"$arg\"" - fi - i=`expr $i + 1` - done - case $i in - 0) set -- ; - 1) set -- "$args0" ; - 2) set -- "$args0" "$args1" ; - 3) set -- "$args0" "$args1" "$args2" ; - 4) set -- "$args0" "$args1" "$args2" "$args3" ; - 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ; - 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ; - 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ; - 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ; - 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ; - esac fi +# Now convert the arguments - kludge to limit ourselves to /bin/sh + i=0 +for arg in "$@" ; do +CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` +CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option + +if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition + eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` +else +eval `echo args$i`="\"$arg\"" +fi + i=`expr $i + 1` +done +case $i in +0) set -- ;; +1) set -- "$args0" ;; +2) set -- "$args0" "$args1" ;; +3) set -- "$args0" "$args1" "$args2" ;; +4) set -- "$args0" "$args1" "$args2" "$args3" ;; +5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; +6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; +7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; +8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; +9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; +esac + fi # Escape application args save () { diff --git a/library/build.gradle b/library/build.gradle index 4ba91b4..8d59ccf 100644 --- a/library/build.gradle +++ b/library/build.gradle @@ -36,7 +36,6 @@ android { } dependencies { - implementation 'androidx.core:core-ktx:1.12.0' implementation 'androidx.appcompat:appcompat:1.6.1' implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.6.2' @@ -45,15 +44,13 @@ dependencies { implementation "androidx.compose.runtime:runtime-livedata:$compose_version" implementation "com.google.accompanist:accompanist-pager:0.23.1" implementation "com.google.accompanist:accompanist-flowlayout:0.26.4-beta" - testImplementation 'junit:junit:4.13.2' - androidTestImplementation 'androidx.test.ext:junit:1.1.5' - androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1' - androidTestImplementation "org.mockito.kotlin:mockito-kotlin:4.0.0" - // lifecycle implementation "androidx.lifecycle:lifecycle-viewmodel-compose:2.6.2" - - - // Compose testing dependencies - androidTestImplementation "androidx.compose.ui:ui-test-junit4:$rootProject.compose_version" debugImplementation "androidx.compose.ui:ui-test-manifest:$rootProject.compose_version" + testImplementation "junit:junit:4.13.2" + testImplementation "org.mockito.kotlin:mockito-kotlin:4.0.0" + testImplementation "org.jetbrains.kotlinx:kotlinx-coroutines-test-jvm:1.6.4" + androidTestImplementation "androidx.test.ext:junit:1.1.5" + androidTestImplementation "androidx.test.espresso:espresso-core:3.5.1" + androidTestImplementation "org.mockito.kotlin:mockito-kotlin:4.0.0" + androidTestImplementation "androidx.compose.ui:ui-test-junit4:$rootProject.compose_version" } \ No newline at end of file diff --git a/library/src/main/java/com/mabn/calendarlibrary/CalendarViewModel.kt b/library/src/main/java/com/mabn/calendarlibrary/CalendarViewModel.kt index a092eef..58edbd8 100644 --- a/library/src/main/java/com/mabn/calendarlibrary/CalendarViewModel.kt +++ b/library/src/main/java/com/mabn/calendarlibrary/CalendarViewModel.kt @@ -3,7 +3,9 @@ package com.mabn.calendarlibrary import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import com.mabn.calendarlibrary.core.CalendarIntent +import com.mabn.calendarlibrary.core.DateTimeConstants import com.mabn.calendarlibrary.core.Period +import com.mabn.calendarlibrary.core.RelativePosition import com.mabn.calendarlibrary.utils.* import com.mabn.calendarlibrary.utils.getNextDates import com.mabn.calendarlibrary.utils.getRemainingDatesInWeek @@ -15,6 +17,7 @@ import java.time.LocalDate import java.time.YearMonth class CalendarViewModel : ViewModel() { + private val _visibleDates = MutableStateFlow( calculateCollapsedCalendarDays( @@ -29,12 +32,16 @@ class CalendarViewModel : ViewModel() { val currentMonth: StateFlow get() = calendarExpanded.zip(visibleDates) { isExpanded, dates -> if (isExpanded) { - dates[1][dates[1].size / 2].yearMonth() + dates[RelativePosition.CURRENT.ordinal][dates[RelativePosition.CURRENT.ordinal].size / 2].yearMonth() } else { - if (dates[1].count { it.month == dates[1][0].month } > 3) - dates[1][0].yearMonth() - else - dates[1][dates[1].size - 1].yearMonth() + if (dates[RelativePosition.CURRENT.ordinal].count { it.month == dates[RelativePosition.CURRENT.ordinal].first().month } > RelativePosition.values().size + ) { + dates[RelativePosition.CURRENT.ordinal].first() + .yearMonth() + } else { + dates[RelativePosition.CURRENT.ordinal].last() + .yearMonth() + } } }.stateIn(viewModelScope, SharingStarted.Eagerly, LocalDate.now().yearMonth()) @@ -47,11 +54,14 @@ class CalendarViewModel : ViewModel() { when (intent) { CalendarIntent.ExpandCalendar -> { calculateCalendarDates( - startDate = currentMonth.value.minusMonths(1).atDay(1), + startDate = currentMonth.value + .minusMonths(1) + .atDay(1), period = Period.MONTH ) _calendarExpanded.value = true } + CalendarIntent.CollapseCalendar -> { calculateCalendarDates( startDate = calculateCollapsedCalendarVisibleStartDay() @@ -61,9 +71,11 @@ class CalendarViewModel : ViewModel() { ) _calendarExpanded.value = false } + is CalendarIntent.LoadNextDates -> { calculateCalendarDates(intent.startDate, intent.period) } + is CalendarIntent.SelectDate -> { viewModelScope.launch { _selectedDate.emit(intent.date) @@ -87,7 +99,8 @@ class CalendarViewModel : ViewModel() { } private fun calculateCollapsedCalendarVisibleStartDay(): LocalDate { - val halfOfMonth = visibleDates.value[1][visibleDates.value[1].size / 2] + val halfOfMonth = + visibleDates.value[RelativePosition.CURRENT.ordinal][visibleDates.value[RelativePosition.CURRENT.ordinal].size / 2] val visibleMonth = YearMonth.of(halfOfMonth.year, halfOfMonth.month) return if (selectedDate.value.month == visibleMonth.month && selectedDate.value.year == visibleMonth.year) selectedDate.value @@ -95,14 +108,14 @@ class CalendarViewModel : ViewModel() { } private fun calculateCollapsedCalendarDays(startDate: LocalDate): Array> { - val dates = startDate.getNextDates(21) - return Array(3) { - dates.slice(it * 7 until (it + 1) * 7) + val dates = startDate.getNextDates(RelativePosition.values().size * DateTimeConstants.DAYS_IN_WEEK) + return Array(RelativePosition.values().size) { + dates.slice(it * DateTimeConstants.DAYS_IN_WEEK until (it + 1) * DateTimeConstants.DAYS_IN_WEEK) } } private fun calculateExpandedCalendarDays(startDate: LocalDate): Array> { - val array = Array(3) { monthIndex -> + val array = Array(RelativePosition.values().size) { monthIndex -> val monthFirstDate = startDate.plusMonths(monthIndex.toLong()) val monthLastDate = monthFirstDate.plusMonths(1).minusDays(1) val weekBeginningDate = monthFirstDate.getWeekStartDate() diff --git a/library/src/main/java/com/mabn/calendarlibrary/component/CalendarPager.kt b/library/src/main/java/com/mabn/calendarlibrary/component/CalendarPager.kt index 3653832..e1e31db 100644 --- a/library/src/main/java/com/mabn/calendarlibrary/component/CalendarPager.kt +++ b/library/src/main/java/com/mabn/calendarlibrary/component/CalendarPager.kt @@ -8,6 +8,7 @@ import androidx.compose.ui.Alignment import com.google.accompanist.pager.ExperimentalPagerApi import com.google.accompanist.pager.HorizontalPager import com.google.accompanist.pager.rememberPagerState +import com.mabn.calendarlibrary.core.RelativePosition import java.time.LocalDate @OptIn(ExperimentalPagerApi::class) @@ -19,22 +20,22 @@ internal fun CalendarPager( content: @Composable (currentPage: Int) -> Unit ) { val initialized = remember { mutableStateOf(false) } - val pagerState = rememberPagerState(initialPage = 1) + val pagerState = rememberPagerState(initialPage = RelativePosition.CURRENT.ordinal) LaunchedEffect(pagerState.currentPage) { - if (pagerState.currentPage == 2) { - loadNextDates(loadedDates[1][0]) - pagerState.scrollToPage(1) + if (pagerState.currentPage == RelativePosition.NEXT.ordinal) { + loadNextDates(loadedDates[RelativePosition.CURRENT.ordinal].first()) + pagerState.scrollToPage(RelativePosition.CURRENT.ordinal) } - if (pagerState.currentPage == 0 && initialized.value) { - loadPrevDates(loadedDates[0][0]) - pagerState.scrollToPage(1) + if (pagerState.currentPage == RelativePosition.PREVIOUS.ordinal && initialized.value) { + loadPrevDates(loadedDates[RelativePosition.PREVIOUS.ordinal].first()) + pagerState.scrollToPage(RelativePosition.CURRENT.ordinal) } } LaunchedEffect(Unit) { initialized.value = true } HorizontalPager( - count = 3, + count = RelativePosition.values().size, state = pagerState, verticalAlignment = Alignment.Top ) { currentPage -> diff --git a/library/src/main/java/com/mabn/calendarlibrary/component/InlineCalendar.kt b/library/src/main/java/com/mabn/calendarlibrary/component/InlineCalendar.kt index dfeb6c9..588e5d6 100644 --- a/library/src/main/java/com/mabn/calendarlibrary/component/InlineCalendar.kt +++ b/library/src/main/java/com/mabn/calendarlibrary/component/InlineCalendar.kt @@ -10,6 +10,7 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalConfiguration import androidx.compose.ui.unit.dp import com.mabn.calendarlibrary.core.CalendarTheme +import com.mabn.calendarlibrary.core.DateTimeConstants import com.mabn.calendarlibrary.utils.dayViewModifier import java.time.LocalDate @@ -22,7 +23,7 @@ internal fun InlineCalendar( loadPrevWeek: (endWeekDate: LocalDate) -> Unit, onDayClick: (LocalDate) -> Unit ) { - val itemWidth = LocalConfiguration.current.screenWidthDp / 7 + val itemWidth = LocalConfiguration.current.screenWidthDp / DateTimeConstants.DAYS_IN_WEEK CalendarPager( loadedDates = loadedDates, loadNextDates = loadNextWeek, diff --git a/library/src/main/java/com/mabn/calendarlibrary/component/MonthViewCalendar.kt b/library/src/main/java/com/mabn/calendarlibrary/component/MonthViewCalendar.kt index bc5b096..22073d8 100644 --- a/library/src/main/java/com/mabn/calendarlibrary/component/MonthViewCalendar.kt +++ b/library/src/main/java/com/mabn/calendarlibrary/component/MonthViewCalendar.kt @@ -8,6 +8,7 @@ import androidx.compose.ui.platform.LocalConfiguration import androidx.compose.ui.unit.dp import com.google.accompanist.flowlayout.FlowRow import com.mabn.calendarlibrary.core.CalendarTheme +import com.mabn.calendarlibrary.core.DateTimeConstants import com.mabn.calendarlibrary.utils.dayViewModifier import java.time.LocalDate import java.time.YearMonth @@ -21,11 +22,11 @@ internal fun MonthViewCalendar( loadDatesForMonth: (YearMonth) -> Unit, onDayClick: (LocalDate) -> Unit ) { - val itemWidth = LocalConfiguration.current.screenWidthDp / 7 + val itemWidth = LocalConfiguration.current.screenWidthDp / DateTimeConstants.DAYS_IN_WEEK CalendarPager( loadedDates = loadedDates, loadNextDates = { loadDatesForMonth(currentMonth) }, - loadPrevDates = { loadDatesForMonth(currentMonth.minusMonths(2)) } // why 2 + loadPrevDates = { loadDatesForMonth(currentMonth.minusMonths(2)) } ) { currentPage -> FlowRow(Modifier.height(355.dp)) { loadedDates[currentPage].forEachIndexed { index, date -> @@ -40,7 +41,7 @@ internal fun MonthViewCalendar( theme = theme, isSelected = selectedDate == date, onDayClick = { onDayClick(date) }, - weekDayLabel = index < 7, + weekDayLabel = index < DateTimeConstants.DAYS_IN_WEEK, modifier = Modifier.dayViewModifier(date, currentMonth, monthView = true) ) } diff --git a/library/src/main/java/com/mabn/calendarlibrary/core/CalendarIntent.kt b/library/src/main/java/com/mabn/calendarlibrary/core/CalendarIntent.kt index 4b073c5..151b463 100644 --- a/library/src/main/java/com/mabn/calendarlibrary/core/CalendarIntent.kt +++ b/library/src/main/java/com/mabn/calendarlibrary/core/CalendarIntent.kt @@ -11,6 +11,6 @@ sealed class CalendarIntent { class SelectDate(val date: LocalDate) : CalendarIntent() - object ExpandCalendar : CalendarIntent() - object CollapseCalendar : CalendarIntent() + data object ExpandCalendar : CalendarIntent() + data object CollapseCalendar : CalendarIntent() } diff --git a/library/src/main/java/com/mabn/calendarlibrary/core/DateTimeConstants.kt b/library/src/main/java/com/mabn/calendarlibrary/core/DateTimeConstants.kt new file mode 100644 index 0000000..620fa93 --- /dev/null +++ b/library/src/main/java/com/mabn/calendarlibrary/core/DateTimeConstants.kt @@ -0,0 +1,7 @@ +package com.mabn.calendarlibrary.core + +class DateTimeConstants() { + companion object { + const val DAYS_IN_WEEK = 7 + } +} diff --git a/library/src/main/java/com/mabn/calendarlibrary/core/TimePeriodType.kt b/library/src/main/java/com/mabn/calendarlibrary/core/TimePeriodType.kt new file mode 100644 index 0000000..f59c89f --- /dev/null +++ b/library/src/main/java/com/mabn/calendarlibrary/core/TimePeriodType.kt @@ -0,0 +1,7 @@ +package com.mabn.calendarlibrary.core + +enum class RelativePosition { + PREVIOUS, + CURRENT, + NEXT +} \ No newline at end of file diff --git a/library/src/test/java/com/mabn/calendarlibrary/CalendarViewModelTest.kt b/library/src/test/java/com/mabn/calendarlibrary/CalendarViewModelTest.kt new file mode 100644 index 0000000..7c4c2a2 --- /dev/null +++ b/library/src/test/java/com/mabn/calendarlibrary/CalendarViewModelTest.kt @@ -0,0 +1,85 @@ +package com.mabn.calendarlibrary + +import com.mabn.calendarlibrary.core.CalendarIntent +import com.mabn.calendarlibrary.core.Period +import com.mabn.calendarlibrary.core.RelativePosition +import junit.framework.TestCase.assertEquals +import junit.framework.TestCase.assertFalse +import junit.framework.TestCase.assertTrue +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.test.TestDispatcher +import kotlinx.coroutines.test.UnconfinedTestDispatcher +import kotlinx.coroutines.test.advanceUntilIdle +import kotlinx.coroutines.test.runTest +import kotlinx.coroutines.test.setMain +import org.junit.Before +import org.junit.Test +import org.mockito.InjectMocks +import org.mockito.MockitoAnnotations +import java.time.LocalDate + +class CalendarViewModelTest { + + @InjectMocks + private lateinit var calendarViewModel: CalendarViewModel + + @OptIn(ExperimentalCoroutinesApi::class) + private val testDispatcher: TestDispatcher = UnconfinedTestDispatcher() + + + @Before + @OptIn(ExperimentalCoroutinesApi::class) + fun setup() { + MockitoAnnotations.openMocks(this) + Dispatchers.setMain(testDispatcher) + } + + @Test + fun `should expand calendar`() { + calendarViewModel.onIntent(CalendarIntent.ExpandCalendar) + assertTrue(calendarViewModel.calendarExpanded.value) + } + + @Test + fun `should collapse calendar`() { + calendarViewModel.onIntent(CalendarIntent.CollapseCalendar) + assertFalse(calendarViewModel.calendarExpanded.value) + } + + @Test + fun `should select date`() { + val date = LocalDate.now() + calendarViewModel.onIntent(CalendarIntent.SelectDate(date)) + assertEquals(date, calendarViewModel.selectedDate.value) + } + + @OptIn(ExperimentalCoroutinesApi::class) + @Test + fun `should load next week`() { + val beginningOfCurrentWeek = LocalDate.now() + .minusDays(LocalDate.now().dayOfWeek.value.toLong() - 1) + val beginningOfNextWeek = beginningOfCurrentWeek + .plusWeeks(1) + val endOfNextWeek = beginningOfCurrentWeek + .plusWeeks(2) + .minusDays(1) + runTest { + calendarViewModel.onIntent( + CalendarIntent.LoadNextDates( + beginningOfCurrentWeek, + Period.WEEK + ) + ) + advanceUntilIdle() + assertEquals( + beginningOfNextWeek, + calendarViewModel.visibleDates.value[RelativePosition.CURRENT.ordinal].first() + ) + assertEquals( + endOfNextWeek, + calendarViewModel.visibleDates.value[RelativePosition.CURRENT.ordinal].last() + ) + } + } +} \ No newline at end of file diff --git a/library/src/test/java/com/mabn/calendarlibrary/LocalDateExtensionTest.kt b/library/src/test/java/com/mabn/calendarlibrary/LocalDateExtensionTest.kt index 01e8327..bf6247d 100644 --- a/library/src/test/java/com/mabn/calendarlibrary/LocalDateExtensionTest.kt +++ b/library/src/test/java/com/mabn/calendarlibrary/LocalDateExtensionTest.kt @@ -9,30 +9,30 @@ import java.time.DayOfWeek import java.time.LocalDate -internal class LocalDateExtensionTest{ +internal class LocalDateExtensionTest { @Test - fun `get remaining dates in month`(){ + fun `should get remaining dates in month`() { val date = LocalDate.of(2022, 8, 29) val remainingDays = date.getRemainingDatesInMonth() - Assert.assertEquals(3,remainingDays.size) + Assert.assertEquals(3, remainingDays.size) Assert.assertEquals(LocalDate.of(2022, 8, 29), remainingDays[0]) - Assert.assertEquals( LocalDate.of(2022, 8,31),remainingDays[2]) + Assert.assertEquals(LocalDate.of(2022, 8, 31), remainingDays[2]) } @Test - fun `get remaining dates in week`(){ - val date = LocalDate.of(2022,9,30) + fun `should get remaining dates in week`() { + val date = LocalDate.of(2022, 9, 30) val remainingDays = date.getRemainingDatesInWeek() Assert.assertEquals(2, remainingDays.size) Assert.assertEquals(LocalDate.of(2022, 10, 1), remainingDays[0]) - Assert.assertEquals( LocalDate.of(2022, 10,2),remainingDays[1]) + Assert.assertEquals(LocalDate.of(2022, 10, 2), remainingDays[1]) } @Test - fun `get date for the first day of the week (default monday)`() { + fun `should get date for the first day of the week (default monday)`() { val date = LocalDate.of(2022, 9, 21) - Assert.assertEquals(date.dayOfWeek, DayOfWeek.WEDNESDAY) val startWeekDate = date.getWeekStartDate() + Assert.assertEquals(date.dayOfWeek, DayOfWeek.WEDNESDAY) Assert.assertEquals(startWeekDate.dayOfWeek, DayOfWeek.MONDAY) Assert.assertEquals(startWeekDate.dayOfMonth, 19) Assert.assertEquals(startWeekDate.monthValue, 9) @@ -40,10 +40,10 @@ internal class LocalDateExtensionTest{ } @Test - fun `get date for the first day of the week which is sunday`() { + fun `should get date for the first day of the week which is sunday`() { val date = LocalDate.of(2022, 9, 21) - Assert.assertEquals(date.dayOfWeek, DayOfWeek.WEDNESDAY) val startWeekDate = date.getWeekStartDate(DayOfWeek.SUNDAY) + Assert.assertEquals(date.dayOfWeek, DayOfWeek.WEDNESDAY) Assert.assertEquals(startWeekDate.dayOfWeek, DayOfWeek.SUNDAY) Assert.assertEquals(startWeekDate.dayOfMonth, 18) Assert.assertEquals(startWeekDate.monthValue, 9)