Wrote unit tests for Alarm
This commit is contained in:
parent
e9b99880d7
commit
2a5b6db25c
@ -22,7 +22,10 @@ android {
|
|||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
compile fileTree(dir: 'libs', include: ['*.jar'])
|
compile fileTree(dir: 'libs', include: ['*.jar'])
|
||||||
|
// Required -- JUnit 4 framework
|
||||||
testCompile 'junit:junit:4.12'
|
testCompile 'junit:junit:4.12'
|
||||||
|
// Optional -- Mockito framework
|
||||||
|
testCompile 'org.mockito:mockito-core:1.10.19'
|
||||||
provided 'com.google.auto.value:auto-value:1.2'
|
provided 'com.google.auto.value:auto-value:1.2'
|
||||||
apt 'com.google.auto.value:auto-value:1.2'
|
apt 'com.google.auto.value:auto-value:1.2'
|
||||||
compile 'com.android.support:appcompat-v7:23.2.1'
|
compile 'com.android.support:appcompat-v7:23.2.1'
|
||||||
|
|||||||
@ -1,5 +1,7 @@
|
|||||||
package com.philliphsu.clock;
|
package com.philliphsu.clock;
|
||||||
|
|
||||||
|
import android.support.annotation.NonNull;
|
||||||
|
|
||||||
import com.google.auto.value.AutoValue;
|
import com.google.auto.value.AutoValue;
|
||||||
|
|
||||||
import java.util.Calendar;
|
import java.util.Calendar;
|
||||||
@ -38,13 +40,10 @@ public abstract class Alarm {
|
|||||||
/** Initializes a Builder to the same property values as this instance */
|
/** Initializes a Builder to the same property values as this instance */
|
||||||
public abstract Builder toBuilder();
|
public abstract Builder toBuilder();
|
||||||
|
|
||||||
public static void main(String[] args) {
|
|
||||||
Alarm a = Alarm.builder().build();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Builder builder() {
|
public static Builder builder() {
|
||||||
// Unfortunately, default values must be provided for generated Builders.
|
// Unfortunately, default values must be provided for generated Builders.
|
||||||
// Fields that were not set when build() is called will throw an exception.
|
// Fields that were not set when build() is called will throw an exception.
|
||||||
|
// TODO: How can QualityMatters get away with not setting defaults?????
|
||||||
return new AutoValue_Alarm.Builder()
|
return new AutoValue_Alarm.Builder()
|
||||||
.id(-1)
|
.id(-1)
|
||||||
.hour(0)
|
.hour(0)
|
||||||
@ -55,17 +54,17 @@ public abstract class Alarm {
|
|||||||
.vibrates(false);
|
.vibrates(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public final void snooze(int minutes) {
|
public void snooze(int minutes) {
|
||||||
if (minutes <= 0 || minutes > MAX_MINUTES_CAN_SNOOZE)
|
if (minutes <= 0 || minutes > MAX_MINUTES_CAN_SNOOZE)
|
||||||
throw new IllegalArgumentException("Cannot snooze for "+minutes+" minutes");
|
throw new IllegalArgumentException("Cannot snooze for "+minutes+" minutes");
|
||||||
snoozingUntilMillis = System.currentTimeMillis() + minutes * 60000;
|
snoozingUntilMillis = System.currentTimeMillis() + minutes * 60000;
|
||||||
}
|
}
|
||||||
|
|
||||||
public final long snoozingUntil() {
|
public long snoozingUntil() {
|
||||||
return snoozingUntilMillis;
|
return snoozingUntilMillis;
|
||||||
}
|
}
|
||||||
|
|
||||||
public final boolean isSnoozed() {
|
public boolean isSnoozed() {
|
||||||
if (snoozingUntilMillis <= System.currentTimeMillis()) {
|
if (snoozingUntilMillis <= System.currentTimeMillis()) {
|
||||||
snoozingUntilMillis = 0;
|
snoozingUntilMillis = 0;
|
||||||
return false;
|
return false;
|
||||||
@ -73,31 +72,31 @@ public abstract class Alarm {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public final void setEnabled(boolean enabled) {
|
public void setEnabled(boolean enabled) {
|
||||||
this.enabled = enabled;
|
this.enabled = enabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
public final boolean isEnabled() {
|
public boolean isEnabled() {
|
||||||
return enabled;
|
return enabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
public final void setRecurring(int day, boolean recurring) {
|
public void setRecurring(int day, boolean recurring) {
|
||||||
checkDay(day);
|
checkDay(day);
|
||||||
recurringDays()[day] = recurring;
|
recurringDays()[day] = recurring;
|
||||||
}
|
}
|
||||||
|
|
||||||
public final boolean isRecurring(int day) {
|
public boolean isRecurring(int day) {
|
||||||
checkDay(day);
|
checkDay(day);
|
||||||
return recurringDays()[day];
|
return recurringDays()[day];
|
||||||
}
|
}
|
||||||
|
|
||||||
public final boolean hasRecurrence() {
|
public boolean hasRecurrence() {
|
||||||
for (boolean b : recurringDays())
|
for (boolean b : recurringDays())
|
||||||
if (b) return true;
|
if (b) return true;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public final long ringsAt() {
|
public long ringsAt() {
|
||||||
// Always with respect to the current date and time
|
// Always with respect to the current date and time
|
||||||
Calendar calendar = new GregorianCalendar();
|
Calendar calendar = new GregorianCalendar();
|
||||||
calendar.set(Calendar.HOUR_OF_DAY, hour());
|
calendar.set(Calendar.HOUR_OF_DAY, hour());
|
||||||
@ -127,12 +126,12 @@ public abstract class Alarm {
|
|||||||
return calendar.getTimeInMillis();
|
return calendar.getTimeInMillis();
|
||||||
}
|
}
|
||||||
|
|
||||||
public final long ringsIn() {
|
public long ringsIn() {
|
||||||
return ringsAt() - System.currentTimeMillis();
|
return ringsAt() - System.currentTimeMillis();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @return true if this Alarm will ring in the next {@code hours} hours */
|
/** @return true if this Alarm will ring in the next {@code hours} hours */
|
||||||
public final boolean ringsWithinHours(int hours) {
|
public boolean ringsWithinHours(int hours) {
|
||||||
return ringsIn() <= hours * 3600000;
|
return ringsIn() <= hours * 3600000;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -148,30 +147,39 @@ public abstract class Alarm {
|
|||||||
// and provide an "accumulating" method
|
// and provide an "accumulating" method
|
||||||
abstract boolean[] recurringDays();
|
abstract boolean[] recurringDays();
|
||||||
public final Builder setRecurring(int day, boolean recurs) {
|
public final Builder setRecurring(int day, boolean recurs) {
|
||||||
|
checkDay(day)
|
||||||
recurringDays()[day] = recurs;
|
recurringDays()[day] = recurs;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
public abstract Builder recurringDays(boolean[] recurringDays);
|
public abstract Builder recurringDays(boolean[] recurringDays);
|
||||||
public abstract Builder label(String label);
|
public abstract Builder label(@NonNull String label);
|
||||||
public abstract Builder ringtone(String ringtone);
|
public abstract Builder ringtone(@NonNull String ringtone);
|
||||||
public abstract Builder vibrates(boolean vibrates);
|
public abstract Builder vibrates(boolean vibrates);
|
||||||
// To enforce preconditions, split the build method into two. autoBuild() is hidden from
|
// To enforce preconditions, split the build method into two. autoBuild() is hidden from
|
||||||
// callers and is generated. You implement the public build(), which calls the generated
|
// callers and is generated. You implement the public build(), which calls the generated
|
||||||
// autoBuild() and performs your desired validations.
|
// autoBuild() and performs your desired validations.
|
||||||
/*not public*/abstract Alarm autoBuild();
|
/*not public*/abstract Alarm autoBuild();
|
||||||
|
|
||||||
public final Alarm build() {
|
public Alarm build() {
|
||||||
Alarm alarm = autoBuild();
|
Alarm alarm = autoBuild();
|
||||||
if (alarm.hour() < 0 || alarm.hour() > 23 || alarm.minutes() < 0 || alarm.minutes() > 59) {
|
checkTime(alarm.hour(), alarm.minutes());
|
||||||
throw new IllegalStateException("Hour and minutes invalid");
|
|
||||||
}
|
|
||||||
return alarm;
|
return alarm;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void checkDay(int day) {
|
private static void checkTime(int hour, int minutes) {
|
||||||
|
if (hour < 0 || hour > 23 || minutes < 0 || minutes > 59) {
|
||||||
|
throw new IllegalStateException("Hour and minutes invalid");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void checkDay(int day) {
|
||||||
if (day < SUNDAY || day > SATURDAY)
|
if (day < SUNDAY || day > SATURDAY)
|
||||||
throw new IllegalArgumentException("Invalid day " + day);
|
throw new IllegalArgumentException("Invalid day " + day);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
122
app/src/test/java/com/philliphsu/clock/AlarmTest.java
Normal file
122
app/src/test/java/com/philliphsu/clock/AlarmTest.java
Normal file
@ -0,0 +1,122 @@
|
|||||||
|
package com.philliphsu.clock;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import java.util.Calendar;
|
||||||
|
import java.util.GregorianCalendar;
|
||||||
|
|
||||||
|
import static java.util.Calendar.DAY_OF_MONTH;
|
||||||
|
import static java.util.Calendar.DAY_OF_WEEK;
|
||||||
|
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.MONTH;
|
||||||
|
import static java.util.Calendar.SECOND;
|
||||||
|
import static java.util.Calendar.YEAR;
|
||||||
|
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 testRecurrence() {
|
||||||
|
Alarm alarm = Alarm.builder().build();
|
||||||
|
|
||||||
|
// Some true, some false
|
||||||
|
for (int i = Alarm.SUNDAY; i <= Alarm.SATURDAY; i++) {
|
||||||
|
alarm.setRecurring(i, i % 2 == 0);
|
||||||
|
assertTrue(alarm.isRecurring(i) == (i % 2 == 0));
|
||||||
|
}
|
||||||
|
assertTrue(alarm.hasRecurrence());
|
||||||
|
|
||||||
|
// All false
|
||||||
|
for (int i = Alarm.SUNDAY; i <= Alarm.SATURDAY; i++) {
|
||||||
|
alarm.setRecurring(i, false);
|
||||||
|
assertFalse(alarm.isRecurring(i));
|
||||||
|
}
|
||||||
|
assertFalse(alarm.hasRecurrence());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void alarm_RingsAt_ReturnsCorrectRingTime() {
|
||||||
|
GregorianCalendar now = new GregorianCalendar();
|
||||||
|
for (int h = 0; h < 24; h++) {
|
||||||
|
for (int m = 0; m < 60; m++) {
|
||||||
|
System.out.println(String.format("Testing %02d:%02d", h, m));
|
||||||
|
int hC = now.get(HOUR_OF_DAY); // Current hour
|
||||||
|
int mC = now.get(MINUTE); // Current minute
|
||||||
|
Alarm a = Alarm.builder().hour(h).minutes(m).build();
|
||||||
|
long calculatedRingTime;
|
||||||
|
if (h <= hC) {
|
||||||
|
if (m <= mC) {
|
||||||
|
calculatedRingTime = (23-hC+h)*3600000 + (60-mC+m)*60000;
|
||||||
|
} else {
|
||||||
|
calculatedRingTime = (m-mC)*60000;
|
||||||
|
if (h < hC) {
|
||||||
|
calculatedRingTime += (24-hC+h)*3600000;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (m <= mC) {
|
||||||
|
calculatedRingTime = (h-hC-1)*3600000+(60-mC+m)*60000;
|
||||||
|
} else {
|
||||||
|
calculatedRingTime = (h-hC)*3600000+(m-mC)*60000;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
now.setTimeInMillis(now.getTimeInMillis() + calculatedRingTime);
|
||||||
|
now.set(SECOND, 0);
|
||||||
|
now.set(MILLISECOND, 0);
|
||||||
|
assertEquals(a.ringsAt(), now.getTimeInMillis());
|
||||||
|
// VERY IMPORTANT TO RESET AT THE END!!!! THIS TOOK A WHOLE FUCKING DAY OF BUG HUNTING!!!
|
||||||
|
now.setTimeInMillis(System.currentTimeMillis());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void snoozeAlarm_AssertEquals_SnoozingUntilMillis_CorrespondsToWallClock() {
|
||||||
|
// Expected
|
||||||
|
Calendar cal = new GregorianCalendar();
|
||||||
|
cal.add(MINUTE, 10);
|
||||||
|
// Actual
|
||||||
|
Calendar snoozeCal = new GregorianCalendar();
|
||||||
|
Alarm alarm = Alarm.builder().build();
|
||||||
|
alarm.snooze(10);
|
||||||
|
snoozeCal.setTimeInMillis(alarm.snoozingUntil());
|
||||||
|
|
||||||
|
assertEquals(cal.get(YEAR), snoozeCal.get(YEAR));
|
||||||
|
assertEquals(cal.get(MONTH), snoozeCal.get(MONTH));
|
||||||
|
assertEquals(cal.get(DAY_OF_MONTH), snoozeCal.get(DAY_OF_MONTH));
|
||||||
|
assertEquals(cal.get(DAY_OF_WEEK), snoozeCal.get(DAY_OF_WEEK));
|
||||||
|
assertEquals(cal.get(HOUR_OF_DAY), snoozeCal.get(HOUR_OF_DAY));
|
||||||
|
assertEquals(cal.get(MINUTE), snoozeCal.get(MINUTE));
|
||||||
|
assertEquals(cal.get(SECOND), snoozeCal.get(SECOND));
|
||||||
|
// Milliseconds not required to be equal, because they will always
|
||||||
|
// have some difference
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void snoozeAlarm_IsSnoozed_ReturnsTrue_ForAllMillisUpToButExcluding_SnoozingUntilMillis() {
|
||||||
|
Alarm alarm = Alarm.builder().build();
|
||||||
|
alarm.snooze(1);
|
||||||
|
// If all iterations leading up to 20ms before the target time evaluate to true,
|
||||||
|
// that is good enough and we don't really care about the last 20ms.
|
||||||
|
while (alarm.snoozingUntil() - System.currentTimeMillis() > 20) {
|
||||||
|
assertTrue(alarm.isSnoozed());
|
||||||
|
}
|
||||||
|
// Wait long enough 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());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue
Block a user