/* * 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.assertEquals; 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.BooleanCell; import ccre.channel.BooleanInput; import ccre.channel.BooleanOutput; import ccre.channel.EventCell; import ccre.channel.EventOutput; import ccre.channel.FloatCell; import ccre.scheduler.VirtualTime; import ccre.testing.CountingEventOutput; @SuppressWarnings("javadoc") public class ExpirationTimerTest { private ExpirationTimer timer; @Before public void setUp() throws Exception { VirtualTime.startFakeTime(); timer = new ExpirationTimer(); timer.start(); timer.stop(); } @After public void tearDown() throws Exception { timer.terminate(); timer = null; VirtualTime.endFakeTime(); } @Test public void testSimple() throws InterruptedException { CountingEventOutput ceo = new CountingEventOutput(); timer.schedule(1000, ceo); VirtualTime.forward(2000); timer.start(); VirtualTime.forward(990); ceo.ifExpected = true; VirtualTime.forward(10); ceo.check(); } @Test public void testScheduleLongEventOutput() throws InterruptedException { CountingEventOutput ceo = new CountingEventOutput(); timer.schedule(1000, ceo); tryFixedScheduling(ceo); } @Test public void testScheduleLong() throws InterruptedException { CountingEventOutput ceo = new CountingEventOutput(); timer.schedule(1000).send(ceo); tryFixedScheduling(ceo); } private void tryFixedScheduling(CountingEventOutput ceo) throws InterruptedException { VirtualTime.forward(1500); timer.start(); VirtualTime.forward(990); ceo.ifExpected = true; VirtualTime.forward(10); ceo.check(); timer.feed(); VirtualTime.forward(990); ceo.ifExpected = true; VirtualTime.forward(10); ceo.check(); timer.stop(); VirtualTime.forward(1500); ceo.check(); } @Test public void testScheduleFloatInputEventOutput() throws InterruptedException { CountingEventOutput ceo = new CountingEventOutput(); FloatCell fs = new FloatCell(1.0f); timer.schedule(fs, ceo); tryVariableScheduling(ceo, fs); } @Test public void testScheduleFloatInput() throws InterruptedException { CountingEventOutput ceo = new CountingEventOutput(); FloatCell fs = new FloatCell(1.0f); timer.schedule(fs).send(ceo); tryVariableScheduling(ceo, fs); } private void tryVariableScheduling(CountingEventOutput ceo, FloatCell fs) throws InterruptedException { VirtualTime.forward(1500); timer.start(); fs.set(0.5f); VirtualTime.forward(990); ceo.ifExpected = true; VirtualTime.forward(10); ceo.check(); timer.feed(); fs.set(1.5f); VirtualTime.forward(490); ceo.ifExpected = true; VirtualTime.forward(10); ceo.check(); timer.stop(); VirtualTime.forward(1500); timer.start(); VirtualTime.forward(1490); ceo.ifExpected = true; VirtualTime.forward(10); ceo.check(); } @Test public void testStartFeedStopSequence() { for (int i = 0; i < 10; i++) { timer.start(); for (int j = 0; j < i % 3; j++) { timer.feed(); } timer.stop(); } } @Test public void testStartStopSequence() { for (int i = 0; i < 10; i++) { timer.start(); timer.stop(); } } @Test(expected = IllegalStateException.class) public void testInvalidStop() { timer.stop(); } @Test(expected = IllegalStateException.class) public void testInvalidStop2() { timer.start(); timer.stop(); timer.stop(); } @Test(expected = IllegalStateException.class) public void testInvalidFeed() { timer.feed(); } @Test(expected = IllegalStateException.class) public void testInvalidFeed2() { timer.start(); timer.stop(); timer.feed(); } @Test(expected = IllegalStateException.class) public void testDoubleStart() { timer.start(); timer.start(); } @Test public void testStartOrFeedInitial() { timer.startOrFeed(); } @Test public void testStartOrFeedRepeated() { timer.startOrFeed(); timer.startOrFeed(); } @Test public void testStartOrFeedSecondary() { timer.start(); timer.startOrFeed(); } @Test public void testFeedPartialRepeat() throws InterruptedException { CountingEventOutput ceo = new CountingEventOutput(); timer.schedule(1000, ceo); CountingEventOutput ceo2 = new CountingEventOutput(); timer.schedule(1500, ceo2); timer.start(); VirtualTime.forward(990); ceo.ifExpected = true; VirtualTime.forward(10); ceo.check(); VirtualTime.forward(490); timer.feed(); VirtualTime.forward(990); ceo.ifExpected = true; VirtualTime.forward(10); ceo.check(); VirtualTime.forward(490); ceo2.ifExpected = true; VirtualTime.forward(10); ceo.check(); ceo2.check(); } @Test public void testStopPartial() throws InterruptedException { CountingEventOutput ceo = new CountingEventOutput(); timer.schedule(1000, ceo); CountingEventOutput ceo2 = new CountingEventOutput(); timer.schedule(1500, ceo2); timer.start(); VirtualTime.forward(990); ceo.ifExpected = true; VirtualTime.forward(10); ceo.check(); VirtualTime.forward(490); timer.stop(); VirtualTime.forward(600); ceo.check(); ceo2.check(); } @Test public void testGetStartEvent() throws InterruptedException { EventOutput start = timer.getStartEvent(); tryStartEvent(start); } @Test public void testStartWhen() throws InterruptedException { EventCell start = new EventCell(); timer.startWhen(start); tryStartEvent(start); } private void tryStartEvent(EventOutput start) throws InterruptedException { CountingEventOutput ceo = new CountingEventOutput(); timer.schedule(1000, ceo); VirtualTime.forward(1000); start.event(); VirtualTime.forward(990); start.event();// should be ignored ceo.ifExpected = true; VirtualTime.forward(10); ceo.check(); VirtualTime.forward(2000); ceo.check(); } @Test public void testGetStartOrFeedEvent() throws InterruptedException { EventOutput startOrFeed = timer.getStartOrFeedEvent(); tryStartOrFeedEvent(startOrFeed); } @Test public void testStartOrFeedWhen() throws InterruptedException { EventCell startOrFeed = new EventCell(); timer.startOrFeedWhen(startOrFeed); tryStartOrFeedEvent(startOrFeed); } private void tryStartOrFeedEvent(EventOutput startOrFeed) throws InterruptedException { CountingEventOutput ceo = new CountingEventOutput(); timer.schedule(1000, ceo); VirtualTime.forward(1000); startOrFeed.event(); VirtualTime.forward(990); startOrFeed.event();// should not be ignored VirtualTime.forward(990); ceo.ifExpected = true; VirtualTime.forward(10); ceo.check(); VirtualTime.forward(2000); ceo.check(); } @Test public void testGetFeedEventNotRunning() throws InterruptedException { EventOutput feed = timer.getFeedEvent(); tryFeedEventNotRunning(feed); } @Test public void testFeedWhenNotRunning() throws InterruptedException { EventCell feed = new EventCell(); timer.feedWhen(feed); tryFeedEventNotRunning(feed); } private void tryFeedEventNotRunning(EventOutput feed) throws InterruptedException { CountingEventOutput ceo = new CountingEventOutput(); timer.schedule(1000, ceo); timer.start(); ceo.ifExpected = true; VirtualTime.forward(1000); ceo.check(); // flaky; 1 failure timer.stop(); feed.event(); VirtualTime.forward(2000); feed.event(); ceo.check(); } @Test public void testGetFeedEventRunning() throws InterruptedException { EventOutput feed = timer.getFeedEvent(); tryFeedEventRunning(feed); } @Test public void testFeedWhenRunning() throws InterruptedException { EventCell feed = new EventCell(); timer.feedWhen(feed); tryFeedEventRunning(feed); } private void tryFeedEventRunning(EventOutput feed) throws InterruptedException { CountingEventOutput ceo = new CountingEventOutput(); timer.schedule(1000, ceo); VirtualTime.forward(1000); timer.start(); VirtualTime.forward(990); feed.event();// should not be ignored VirtualTime.forward(990); ceo.ifExpected = true; VirtualTime.forward(10); ceo.check(); VirtualTime.forward(2000); ceo.check(); } @Test public void testGetStopEventSafe() { timer.getStopEvent().event(); } @Test public void testGetStopEvent() throws InterruptedException { EventOutput stop = timer.getStopEvent(); tryStopEvent(stop); } @Test public void testStopWhen() throws InterruptedException { EventCell stop = new EventCell(); timer.stopWhen(stop); tryStopEvent(stop); } private void tryStopEvent(EventOutput stop) throws InterruptedException { CountingEventOutput ceo = new CountingEventOutput(); timer.schedule(1000, ceo); CountingEventOutput ceo2 = new CountingEventOutput(); timer.schedule(1500, ceo2); timer.start(); VirtualTime.forward(990); ceo.ifExpected = true; VirtualTime.forward(10); ceo.check(); // NOTE: flaky here: 1 nonoccurrence. VirtualTime.forward(490); stop.event(); VirtualTime.forward(600); ceo.check(); ceo2.check(); } @Test public void testGetRunningControl() throws InterruptedException { BooleanOutput control = timer.getRunningControl(); CountingEventOutput ceo = new CountingEventOutput(); timer.schedule(1000, ceo); CountingEventOutput ceo2 = new CountingEventOutput(); timer.schedule(1500, ceo2); VirtualTime.forward(2000); control.set(true); VirtualTime.forward(990); ceo.ifExpected = true; VirtualTime.forward(10); ceo.check(); VirtualTime.forward(490); control.set(false); VirtualTime.forward(2000); ceo.check(); ceo2.check(); } @Test(expected = NullPointerException.class) public void testRunWhenNull() { timer.runWhen(null); } @Test public void testRunWhen() throws InterruptedException { BooleanCell run = new BooleanCell(); timer.runWhen(run); CountingEventOutput ceo = new CountingEventOutput(); timer.schedule(1000, ceo); CountingEventOutput ceo2 = new CountingEventOutput(); timer.schedule(1500, ceo2); VirtualTime.forward(2000); run.set(true); VirtualTime.forward(990); ceo.ifExpected = true; VirtualTime.forward(10); ceo.check(); VirtualTime.forward(490); run.set(false); VirtualTime.forward(2000); ceo.check(); ceo2.check(); } @Test public void testGetRunning_Write() throws InterruptedException { BooleanOutput control = timer.getRunning(); CountingEventOutput ceo = new CountingEventOutput(); timer.schedule(1000, ceo); CountingEventOutput ceo2 = new CountingEventOutput(); timer.schedule(1500, ceo2); VirtualTime.forward(2000); control.set(true); VirtualTime.forward(990); ceo.ifExpected = true; VirtualTime.forward(10); ceo.check(); VirtualTime.forward(490); control.set(false); VirtualTime.forward(2000); ceo.check(); ceo2.check(); } @Test public void testGetRunning_Read() { BooleanInput running = timer.getRunning(); for (int i = 0; i < 3; i++) { assertFalse(running.get()); timer.start(); assertTrue(running.get()); timer.feed(); assertTrue(running.get()); timer.feed(); assertTrue(running.get()); timer.stop(); assertFalse(running.get()); } } @Test public void testGetRunningStatus() { BooleanInput running = timer.getRunningStatus(); for (int i = 0; i < 3; i++) { assertFalse(running.get()); timer.start(); assertTrue(running.get()); timer.feed(); assertTrue(running.get()); timer.feed(); assertTrue(running.get()); timer.stop(); assertFalse(running.get()); } } @Test public void testIsRunning() throws InterruptedException { for (int i = 0; i < 3; i++) { checkRunning(false); timer.start(); checkRunning(true); timer.feed(); checkRunning(true); timer.feed(); checkRunning(true); timer.stop(); checkRunning(false); } } private void checkRunning(boolean running) throws InterruptedException { assertEquals(running, timer.isRunning()); VirtualTime.forward(100); assertEquals(running, timer.isRunning()); } }