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()); } }