Clockplus/app/src/test/java/com/philliphsu/clock2/AlarmTest.java
2016-06-13 02:15:13 -07:00

500 lines
19 KiB
Java

package com.philliphsu.clock2;
import org.junit.Test;
import java.util.Calendar;
import java.util.GregorianCalendar;
import static com.philliphsu.clock2.DaysOfWeek.SATURDAY;
import static com.philliphsu.clock2.DaysOfWeek.SUNDAY;
import static java.lang.System.out;
import static java.util.Calendar.HOUR_OF_DAY;
import static java.util.Calendar.MILLISECOND;
import static java.util.Calendar.MINUTE;
import static java.util.Calendar.SECOND;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
/**
* Created by Phillip Hsu on 5/27/2016.
*/
public class AlarmTest {
@Test
public void setRecurringDays_VerifyElementsSetCorrectly() {
Alarm alarm = Alarm.builder().build();
// Some true, some false
for (int i = SUNDAY; i <= SATURDAY; i++) {
alarm.setRecurring(i, i % 2 == 0);
assertTrue(alarm.isRecurring(i) == (i % 2 == 0));
}
assertTrue(alarm.hasRecurrence());
// All false
for (int i = SUNDAY; i <= SATURDAY; i++) {
alarm.setRecurring(i, false);
assertFalse(alarm.isRecurring(i));
}
assertFalse(alarm.hasRecurrence());
try {
alarm.setRecurring(7, true);
alarm.setRecurring(-3, false);
} catch (IllegalArgumentException e) {
out.println("Caught setting recurrence for invalid days");
}
}
@Test
public void alarm_RingsAt_NoRecurrence_ReturnsCorrectRingTime() {
GregorianCalendar now = new GregorianCalendar();
for (int h = 0; h < 24; h++) {
for (int m = 0; m < 60; m++) {
out.println(String.format("Testing %02d:%02d", h, m));
Alarm a = Alarm.builder().hour(h).minutes(m).build();
calculateRingTimeAndTest(h, m, 0 /*days*/, now, a.ringsAt());
}
}
}
@Test
public void alarm_RingsAt_RecurringDays_ReturnsCorrectRingTime() {
Calendar cal = new GregorianCalendar();
int D_C = cal.get(Calendar.DAY_OF_WEEK);
for (int h = 0; h < 24; h++) {
for (int m = 0; m < 60; m++) {
for (int D = Calendar.SUNDAY; D <= Calendar.SATURDAY; D++) {
out.println("Testing (h, m, d) = ("+h+", "+m+", "+ (D-1) +")");
int hC = cal.get(HOUR_OF_DAY); // Current hour
int mC = cal.get(MINUTE); // Current minute
Alarm a = Alarm.builder().hour(h).minutes(m).build();
a.setRecurring(D - 1, true);
int days = 0;
if (h > hC || (h == hC && m > mC)) {
if (D < D_C) {
days = Calendar.SATURDAY - D_C + D;
} else if (D == D_C) {
days = 0; // upcoming on the same day
} else {
days = D - D_C;
}
} else if (h <= hC) {
if (D < D_C) {
days = Calendar.SATURDAY - D_C + D - 1;
} else if (D == D_C) {
days = 6;
} else {
days = D - D_C - 1;
}
}
calculateRingTimeAndTest(h, m, days, cal, a.ringsAt());
}
}
}
}
/*
* Set recurring days in a queue and test that, regardless, ringsAt() ALWAYS returns the ring time
* that is closest to the current day. In other words, the ring time that comes first in the queue.
*/
@Test
public void alarm_RingsAt_ForwardQueueingRecurringDays() {
Calendar cal = new GregorianCalendar();
int D_C = cal.get(Calendar.DAY_OF_WEEK);
for (int h = 0; h < 24; h++) {
for (int m = 0; m < 60; m++) {
Alarm a = Alarm.builder().hour(h).minutes(m).build();
for (int D = Calendar.SUNDAY; D <= Calendar.SATURDAY; D++) {
out.println("Testing (h, m, d) = ("+h+", "+m+", "+ (D-1) +")");
int hC = cal.get(HOUR_OF_DAY); // Current hour
int mC = cal.get(MINUTE); // Current minute
a.setRecurring(D - 1, true);
int days = 0;
if (D == D_C) {
if (h > hC || (h == hC && m > mC)) {
days = 0;
} else if (h <= hC) {
days = 6;
}
}
calculateRingTimeAndTest(h, m, days, cal, a.ringsAt());
}
}
}
}
/*
* Set recurring days in a queue and test that, regardless, ringsAt() ALWAYS returns the ring time
* that is closest to the current day. In other words, the ring time that comes first in the queue.
*/
@Test
public void alarm_RingsAt_BackwardQueueingRecurringDays() {
Calendar cal = new GregorianCalendar();
int D_C = cal.get(Calendar.DAY_OF_WEEK);
for (int h = 0; h < 24; h++) {
for (int m = 0; m < 60; m++) {
Alarm a = Alarm.builder().hour(h).minutes(m).build();
for (int D = Calendar.SATURDAY; D >= Calendar.SUNDAY; D--) {
out.println("Testing (h, m, d) = ("+h+", "+m+", "+ (D-1) +")");
int hC = cal.get(HOUR_OF_DAY); // Current hour
int mC = cal.get(MINUTE); // Current minute
a.setRecurring(D - 1, true);
int days = 0;
if (h > hC || (h == hC && m > mC)) {
if (D < D_C) {
days = Calendar.SATURDAY - D_C + D;
} else if (D == D_C) {
days = 0; // upcoming on the same day
} else {
days = D - D_C;
}
} else if (h <= hC) {
if (D < D_C) {
days = Calendar.SATURDAY - D_C + D - 1;
} else if (D == D_C) {
days = 0;
} else {
days = D - D_C - 1;
}
}
calculateRingTimeAndTest(h, m, days, cal, a.ringsAt());
}
}
}
}
@Test
public void alarm_RingsAt_MiddleOutQueueingRecurringDays() {
Calendar cal = new GregorianCalendar();
int D_C = cal.get(Calendar.DAY_OF_WEEK);
for (int h = 0; h < 24; h++) {
for (int m = 0; m < 60; m++) {
Alarm a = Alarm.builder().hour(h).minutes(m).build();
a.setRecurring(DaysOfWeek.WEDNESDAY, true);
long wednesdayRingTime = a.ringsAt();
for (int D = Calendar.THURSDAY; D <= Calendar.SATURDAY; D++) {
out.println("Wednesday ring time: " + wednesdayRingTime);
// Check that the ring time is always on Wednesday
a.setRecurring(D - 1, true);
assertEquals(wednesdayRingTime, a.ringsAt());
}
for (int D = Calendar.TUESDAY; D >= Calendar.SUNDAY; D--) {
// Check that the ring time is earlier after each iteration
int hC = cal.get(HOUR_OF_DAY); // Current hour
int mC = cal.get(MINUTE); // Current minute
a.setRecurring(D - 1, true);
int days = 0;
if (h > hC || (h == hC && m > mC)) {
if (D < D_C) {
days = Calendar.SATURDAY - D_C + D;
} else if (D == D_C) {
days = 0; // upcoming on the same day
} else {
days = D - D_C;
}
} else if (h <= hC) {
if (D < D_C) {
days = Calendar.SATURDAY - D_C + D - 1;
} else if (D == D_C) {
days = 0;
} else {
days = D - D_C - 1;
}
}
calculateRingTimeAndTest(h, m, days, cal, a.ringsAt());
}
}
}
}
@Test
public void alarm_RingsAt_AllRecurringDays_ReturnsCorrectRingTime() {
// The results of this test should be the same as the normal ringsAt test:
// alarm_RingsAt_NoRecurrence_ReturnsCorrectRingTime().
GregorianCalendar now = new GregorianCalendar();
for (int h = 0; h < 24; h++) {
for (int m = 0; m < 60; m++) {
Alarm a = Alarm.builder().hour(h).minutes(m).build();
for (int i = 0; i < 7; i++) {
a.setRecurring(i, true);
}
calculateRingTimeAndTest(h, m, 0, now, a.ringsAt());
}
}
}
@Test
public void alarm_RingsAt_RecurringDayIsCurrentDay_ReturnsCorrectRingTime() {
Calendar cal = new GregorianCalendar();
int dC = cal.get(Calendar.DAY_OF_WEEK) - 1; // Current week day, converted to our values
for (int h = 0; h < 24; h++) {
for (int m = 0; m < 60; m++) {
int hC = cal.get(HOUR_OF_DAY); // Current hour
int mC = cal.get(MINUTE); // Current minute
Alarm a = Alarm.builder().hour(h).minutes(m).build();
a.setRecurring(dC, true);
// Quantities until the ring time (h, m)
int days = 0;
int hours = 0;
int minutes = 0;
if (h <= hC) {
if (m <= mC) {
days = 6;
hours = 23 - hC + h;
minutes = 60 - mC + m;
} else {
minutes = m - mC;
if (h < hC) {
days = 6;
hours = 24 - hC + h;
}
}
} else {
if (m <= mC) {
hours = h - hC - 1;
minutes = 60 - mC + m;
} else {
hours = h - hC;
minutes = m - mC;
}
}
cal.add(HOUR_OF_DAY, 24 * days);
cal.add(HOUR_OF_DAY, hours);
cal.add(MINUTE, minutes);
cal.set(SECOND, 0);
cal.set(MILLISECOND, 0);
assertEquals(a.ringsAt(), cal.getTimeInMillis());
// VERY IMPORTANT TO RESET AT THE END!!!!
cal.setTimeInMillis(System.currentTimeMillis());
}
}
}
@Test
public void alarm_RingsAt_RecurringDayAfterCurrentDay_ReturnsCorrectRingTime() {
Calendar cal = new GregorianCalendar();
int dC = cal.get(Calendar.DAY_OF_WEEK) - 1; // Current week day, converted to our values
for (int h = 0; h < 24; h++) {
for (int m = 0; m < 60; m++) {
// Start after the current day, using our value. Note that if the current day is Saturday,
// this test won't run anything and would still pass.
for (int d = dC + 1; d <= DaysOfWeek.SATURDAY; d++) {
out.println("Testing (h, m, d) = ("+h+", "+m+", "+d+")");
int hC = cal.get(HOUR_OF_DAY); // Current hour
int mC = cal.get(MINUTE); // Current minute
Alarm a = Alarm.builder().hour(h).minutes(m).build();
a.setRecurring(d, true);
// Quantities until the ring time (h, m)
int days = 0;
int hours = 0;
int minutes = 0;
if (h <= hC) {
if (m <= mC) {
days = d - dC - 1;
hours = 23 - hC + h;
minutes = 60 - mC + m;
} else {
minutes = m - mC;
if (h < hC) {
days = d - dC - 1;
hours = 24 - hC + h;
} else {
// h == hC
days = d - dC;
}
}
} else {
if (m <= mC) {
days = d - dC;
hours = h - hC - 1;
minutes = 60 - mC + m;
} else {
days = d - dC;
hours = h - hC;
minutes = m - mC;
}
}
cal.add(HOUR_OF_DAY, 24 * days);
cal.add(HOUR_OF_DAY, hours);
cal.add(MINUTE, minutes);
cal.set(SECOND, 0);
cal.set(MILLISECOND, 0);
assertEquals(a.ringsAt(), cal.getTimeInMillis());
// VERY IMPORTANT TO RESET AT THE END!!!!
cal.setTimeInMillis(System.currentTimeMillis());
}
}
}
}
@Test
public void alarm_RingsAt_RecurringDayBeforeCurrentDay_ReturnsCorrectRingTime() {
Calendar cal = new GregorianCalendar();
int D_C = cal.get(Calendar.DAY_OF_WEEK); // Current week day as defined in Calendar class
for (int h = 0; h < 24; h++) {
for (int m = 0; m < 60; m++) {
for (int D = Calendar.SUNDAY; D < D_C; D++) {
out.println("Testing (h, m, d) = ("+h+", "+m+", "+(D-1)+")");
int hC = cal.get(HOUR_OF_DAY); // Current hour
int mC = cal.get(MINUTE); // Current minute
Alarm a = Alarm.builder().hour(h).minutes(m).build();
a.setRecurring(D - 1, true);
// Quantities until the ring time (h, m)
int days = 0;
int hours = 0;
int minutes = 0;
if (h <= hC) {
if (m <= mC) {
days = Calendar.SATURDAY - D_C + D - 1;
hours = 23 - hC + h;
minutes = 60 - mC + m;
} else {
minutes = m - mC;
if (h < hC) {
days = Calendar.SATURDAY - D_C + D - 1;
hours = 24 - hC + h;
} else {
// h == hC
days = Calendar.SATURDAY - D_C + D;
}
}
} else {
if (m <= mC) {
days = Calendar.SATURDAY - D_C + D;
hours = h - hC - 1;
minutes = 60 - mC + m;
} else {
days = Calendar.SATURDAY - D_C + D;
hours = h - hC;
minutes = m - mC;
}
}
cal.add(HOUR_OF_DAY, 24 * days);
cal.add(HOUR_OF_DAY, hours);
cal.add(MINUTE, minutes);
cal.set(SECOND, 0);
cal.set(MILLISECOND, 0);
assertEquals(a.ringsAt(), cal.getTimeInMillis());
// VERY IMPORTANT TO RESET AT THE END!!!!
cal.setTimeInMillis(System.currentTimeMillis());
}
}
}
}
@Test
public void snoozeAlarm_AssertEquals_SnoozingUntilMillis_CorrespondsToWallClock() {
Calendar cal = new GregorianCalendar();
cal.add(MINUTE, 10);
Alarm alarm = Alarm.builder().build();
alarm.snooze(10);
// Unlike ring times, the snoozingUntilMillis has seconds and millis components.
// Due to the overhead of computation, the two time values will inherently have some
// millis difference. However, if the difference is meaningfully small enough, then
// for all practical purposes, we can consider them equal.
assertTrue(Math.abs(alarm.snoozingUntil() - cal.getTimeInMillis()) <= 10);
}
@Test
public void snoozeAlarm_IsSnoozed_ReturnsTrue_ForAllMillisUpToButExcluding_SnoozingUntilMillis() {
Alarm alarm = Alarm.builder().build();
alarm.snooze(1);
// Stop 10ms early so System.currentTimeMillis() doesn't exceed the target time in the middle
// of an iteration.
while (System.currentTimeMillis() < alarm.snoozingUntil() - 10) {
assertTrue(alarm.isSnoozed());
}
// Wait just in case so the target time passes.
try {
Thread.sleep(20);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
assertFalse(alarm.isSnoozed());
// Check if the snoozingUntilMillis is cleared
assertEquals(0, alarm.snoozingUntil());
}
}
/**
* Calculates the remaining time until the ring time (h, m) and tests if the
* calculated value agrees with the {@code expected} value. Callers are expected
* to calculate the number of days until this ring time (h, m) themselves, because
* the manner of its calculation is dependent on the recurrence situation.
* @param h the hours of the ring time under test
* @param m the minutes of the ring time under test
* @param days your calculated number of days until this ring time
* @param calendar the Calendar instantiated in your test
* @param expected the expected ring time to be compared against the calculated value
*/
private void calculateRingTimeAndTest(int h, int m, int days, Calendar calendar, long expected) {
int hC = calendar.get(HOUR_OF_DAY); // Current hour
int mC = calendar.get(MINUTE); // Current minute
int hours = 0;
int minutes = 0;
if (h <= hC) {
if (m <= mC) {
hours = 23 - hC + h;
minutes = 60 - mC + m;
} else {
minutes = m - mC;
if (h < hC) {
hours = 24 - hC + h;
}
}
} else {
if (m <= mC) {
hours = h - hC - 1;
minutes = 60 - mC + m;
} else {
hours = h - hC;
minutes = m - mC;
}
}
calendar.add(HOUR_OF_DAY, 24 * days);
calendar.add(HOUR_OF_DAY, hours);
calendar.add(MINUTE, minutes);
calendar.set(SECOND, 0);
calendar.set(MILLISECOND, 0);
long time = calendar.getTimeInMillis();
out.println("Calculated time: " + time);
assertEquals(time, expected);
// RESET AT END!!!!
calendar.setTimeInMillis(System.currentTimeMillis());
}
}