Skip to content

Commit

Permalink
Validation for ensuring a task can not be scheduled before current ti…
Browse files Browse the repository at this point in the history
…me (#169)

* Validation for ensuring a task can be scheduled before current time

* Test for taskForm current time restriction
  • Loading branch information
henneboy authored May 9, 2024
1 parent 1e003a5 commit 83ac1cf
Show file tree
Hide file tree
Showing 3 changed files with 61 additions and 10 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ import dk.scheduling.schedulingfrontend.model.Status
import dk.scheduling.schedulingfrontend.ui.theme.SchedulingFrontendTheme
import java.time.Instant
import java.time.LocalDateTime
import java.time.LocalTime
import java.time.ZoneId

@OptIn(ExperimentalMaterial3Api::class)
Expand Down Expand Up @@ -113,7 +114,7 @@ private fun DialogActions(

data class DateRange(val startTime: Long?, val endTime: Long?) {
private fun millisToLocalDateTime(millis: Long): LocalDateTime =
LocalDateTime.ofInstant(Instant.ofEpochMilli(millis), ZoneId.systemDefault())
LocalDateTime.ofInstant(Instant.ofEpochMilli(millis), ZoneId.systemDefault()).with(LocalTime.MIDNIGHT)

fun rangeStart(): LocalDateTime? = startTime?.let { millisToLocalDateTime(it) }

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,10 +41,15 @@ data class TaskForm(
val start = startDateTime()
val end = endDateTime()
val intervalLengthInMinutes = start.until(end, ChronoUnit.MINUTES)
return if (start.isBefore(end) && intervalLengthInMinutes >= duration.value.toLong()) {
Status(true, "")
} else {
val latestPossibleEventStartTime = end.minus(duration.value.toLong(), ChronoUnit.MINUTES)
return if (!start.isBefore(end)) {
Status(false, "Start time must be before end time, change times or date interval")
} else if (intervalLengthInMinutes < duration.value.toLong()) {
Status(false, "The duration may not be larger than the specified interval")
} else if (LocalDateTime.now().isAfter(latestPossibleEventStartTime)) {
Status(false, "There is not enough time perform the task before the deadline")
} else {
Status(true, "")
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,19 +6,24 @@ import dk.scheduling.schedulingfrontend.components.DateRange
import dk.scheduling.schedulingfrontend.model.Duration
import dk.scheduling.schedulingfrontend.model.TaskForm
import org.junit.Test
import java.time.Instant
import java.time.LocalDateTime

@OptIn(ExperimentalMaterial3Api::class)
class TaskFormTest {
private val timeMidday = TimePickerState(12, 0, true)
private val timeOneMinutePastMidday = TimePickerState(12, 1, true)
private val millisecondsInADay = 86400000L
private val timeSinceEpochInMillis = Instant.now().toEpochMilli()
private val tomorrowInMillis = timeSinceEpochInMillis + millisecondsInADay

@Test
fun statusIsValidTest() {
val taskSameDate =
TaskForm(
1,
Duration("1"),
DateRange(0, 0),
DateRange(tomorrowInMillis, tomorrowInMillis),
timeMidday,
timeOneMinutePastMidday,
)
Expand All @@ -28,11 +33,29 @@ class TaskFormTest {
TaskForm(
1,
Duration("1"),
DateRange(0, Long.MAX_VALUE),
DateRange(timeSinceEpochInMillis, tomorrowInMillis),
timeMidday,
timeMidday,
)
assert(taskDifferentDates.status().isValid) { "Valid task, different dates" }

// Say the current time is 14:10
// Then the start time is 14:00 and end time is 14:20
// The duration of the task is 7 minutes, which fits the interval.
val timeLocal = LocalDateTime.now().minusMinutes(10)
val timeLocalEnd = timeLocal.plusMinutes(20)
val taskTimeNowCloseToEndTime =
TaskForm(
1,
Duration("7"),
DateRange(tomorrowInMillis, tomorrowInMillis),
TimePickerState(timeLocal.hour, timeLocal.minute, true),
TimePickerState(timeLocalEnd.hour, timeLocalEnd.minute, true),
)
// If the task is scheduled instantly, then the event could start at 14:10.
// This would leave enough time to perform the task before the end time:
// 14:10 (current time) + 0:07 (the duration) < 14:20 (end time)
assert(taskTimeNowCloseToEndTime.status().isValid) { "Valid task, end time is after (current time + duration)" }
}

@Test
Expand All @@ -41,7 +64,7 @@ class TaskFormTest {
TaskForm(
1,
Duration("2"),
DateRange(0, 0),
DateRange(tomorrowInMillis, tomorrowInMillis),
timeMidday,
timeOneMinutePastMidday,
)
Expand All @@ -52,8 +75,7 @@ class TaskFormTest {
1,
// 24 hours and one minute in minutes
Duration("1441"),
// One day in minutes
DateRange(0, 86400000),
DateRange(timeSinceEpochInMillis, tomorrowInMillis),
timeMidday,
timeMidday,
)
Expand All @@ -66,10 +88,33 @@ class TaskFormTest {
TaskForm(
null,
Duration("1"),
DateRange(0, 0),
DateRange(tomorrowInMillis, tomorrowInMillis),
timeMidday,
timeOneMinutePastMidday,
)
assert(!taskSameDate.status().isValid) { "Invalid task, deviceId is null (unselected)" }
}

@Test
fun endTime_before_currentTimePlusDuration_InvalidStatus() {
// Say the current time is 14:04
// Then the start time is 14:00 and end time is 14:06
// The duration of the task is 4 minutes, which fits the interval.
val timeLocal = LocalDateTime.now().minusMinutes(4)
val timeLocalEnd = timeLocal.plusMinutes(6)

val timeNowCloseToEndTime =
TaskForm(
1,
Duration("4"),
DateRange(timeSinceEpochInMillis, timeSinceEpochInMillis),
TimePickerState(timeLocal.hour, timeLocal.minute, true),
TimePickerState(timeLocalEnd.hour, timeLocalEnd.minute, true),
)
// The current time is 14:04, and even if the task is instantly scheduled and started/executed,
// then the event would be 14:04.
// But this does not leave enough time to run the 4 minute duration before the end time 14:06
// 14:04 (current time) + 0:04 (the duration) > 14:06 (end time) -> Impossible!
assert(!timeNowCloseToEndTime.status().isValid) { "Invalid task, end time is before (current time + duration)" }
}
}

0 comments on commit 83ac1cf

Please sign in to comment.