/*
* Copyright 2016 Cel Skeggs
*
* This file is part of the CCRE, the Common Chicken Runtime Engine.
*
* The CCRE is free software: you can redistribute it and/or modify it under the
* terms of the GNU Lesser General Public License as published by the Free
* Software Foundation, either version 3 of the License, or (at your option) any
* later version.
*
* The CCRE is distributed in the hope that it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
* A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
* details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with the CCRE. If not, see <http://www.gnu.org/licenses/>.
*/
package ccre.timers;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import ccre.channel.FloatCell;
import ccre.log.LogLevel;
import ccre.log.VerifyingLogger;
import ccre.scheduler.VirtualTime;
import ccre.testing.CountingEventOutput;
@SuppressWarnings("javadoc")
public class PauseTimerTest {
private PauseTimer pt;
@Before
public void setUp() throws Exception {
VirtualTime.startFakeTime();
pt = new PauseTimer(1000);
VerifyingLogger.begin();
}
@After
public void tearDown() throws Exception {
VerifyingLogger.checkAndEnd();
pt.terminate();
pt = null;
VirtualTime.endFakeTime();
}
@Test(expected = IllegalArgumentException.class)
public void testPauseTimerZero() {
new PauseTimer(0);
}
@Test(expected = IllegalArgumentException.class)
public void testPauseTimerNegative() {
new PauseTimer(-1);
}
@Test
public void testPauseTimerSmallPositive() {
new PauseTimer(1);
}
@Test(expected = NullPointerException.class)
public void testPauseTimerNull() {
new PauseTimer(null);
}
@Test
public void testNoDefaultTrigger() throws InterruptedException {
CountingEventOutput con = new CountingEventOutput();
CountingEventOutput coff = new CountingEventOutput();
pt.triggerAtChanges(con, coff);
VirtualTime.forward(700);
VirtualTime.forward(700);
VirtualTime.forward(700);
// if it ever fires here, then ceo will get annoyed
}
@Test
public void testEventAllAtOnce() throws InterruptedException {
CountingEventOutput ceo = new CountingEventOutput();
pt.onRelease().send(ceo);
VirtualTime.forward(2000);
startEvt();
ceo.ifExpected = true;
VirtualTime.forward(1000);
ceo.check();
}
@Test
public void testTriggerVariance() throws InterruptedException {
CountingEventOutput coff = new CountingEventOutput();
FloatCell time = new FloatCell(1.0f);
pt = new PauseTimer(time);
pt.triggerAtEnd(coff);
for (int i = 10; i < 3000; i *= 2) {
time.set(i / 1000f);
pt.event();
VirtualTime.forward(i - 5);
coff.ifExpected = true;
VirtualTime.forward(5);
coff.check();
}
}
@Test
public void testTriggerAtEnd() throws InterruptedException {
CountingEventOutput coff = new CountingEventOutput();
pt.triggerAtEnd(coff);
startEvt();
VirtualTime.forward(990);
coff.ifExpected = true;
VirtualTime.forward(10);
coff.check();
}
@Test
public void testTriggerAtStart() throws InterruptedException {
CountingEventOutput con = new CountingEventOutput();
pt.triggerAtStart(con);
con.ifExpected = true;
startEvt();
con.check();
VirtualTime.forward(1000);
}
@Test
public void testTriggerAtChanges() throws InterruptedException {
CountingEventOutput con = new CountingEventOutput();
CountingEventOutput coff = new CountingEventOutput();
pt.triggerAtChanges(con, coff);
VirtualTime.forward(2000);
con.ifExpected = true;
startEvt();
con.check();
VirtualTime.forward(990);
coff.ifExpected = true;
VirtualTime.forward(10);
coff.check();
}
@Test
public void testEventSequenceMultiPress() throws InterruptedException {
CountingEventOutput con = new CountingEventOutput();
CountingEventOutput coff = new CountingEventOutput();
pt.triggerAtChanges(con, coff);
VirtualTime.forward(2000);
con.ifExpected = true;
startEvt();
con.check();
VirtualTime.forward(500);
startEvt();
VirtualTime.forward(990);
coff.ifExpected = true;
VirtualTime.forward(10);
coff.check();
}
@Test
public void testGet() throws InterruptedException {
assertFalse(pt.get());
startEvt();
assertTrue(pt.get());
for (int i = 0; i < 11; i++) {
VirtualTime.forward(90);
assertTrue(pt.get());
}
VirtualTime.forward(10);
assertFalse(pt.get()); // flaky
}
private void startEvt() throws InterruptedException {
pt.event();
}
@Test
public void testGetMultiEvent() throws InterruptedException {
assertFalse(pt.get());
startEvt();
assertTrue(pt.get());
for (int i = 0; i < 11; i++) {
VirtualTime.forward(90);
assertTrue(pt.get());
}
startEvt();
assertTrue(pt.get());
for (int i = 0; i < 11; i++) {
VirtualTime.forward(90);
assertTrue(pt.get());
}
VirtualTime.forward(10);
assertFalse(pt.get());
}
@Test
public void testStartError() {
CountingEventOutput ceo = new CountingEventOutput();
RuntimeException rtex = new RuntimeException("Purposeful failure.");
pt.triggerAtStart(() -> {
ceo.event();
// TODO: test logging
throw rtex;
});
ceo.ifExpected = true;
VerifyingLogger.configure(LogLevel.SEVERE, "Failure while starting PauseTimer", rtex);
pt.event();
VerifyingLogger.check();
ceo.check();
}
@Test
public void testEndError() throws InterruptedException {
CountingEventOutput ceo = new CountingEventOutput();
RuntimeException rtex = new RuntimeException("Purposeful failure.");
pt.triggerAtEnd(() -> {
ceo.event();
// TODO: test logging
throw rtex;
});
for (int i = 0; i < 10; i++) {
// if something breaks internally, this loop will stop succeeding.
pt.event();
VirtualTime.forward(990);
ceo.ifExpected = true;
VerifyingLogger.configure(LogLevel.SEVERE, "Top-level failure in scheduled event", rtex);
VirtualTime.forward(10);
ceo.check(); // flaky; 5 failures.
VerifyingLogger.check();
}
}
}