/* * 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.scheduler; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import ccre.channel.EventOutput; import ccre.time.FakeTime; import ccre.time.SharedTimeSecrets; import ccre.time.Time; /** * A class of utilities for virtualizing code that needs to be tested based on * changes in time, so that tests don't have to actually wait for time to elapse * or depend on unreliable OS scheduling. * * @author skeggsc */ public class VirtualTime { private static Time oldProvider; private static FakeTime fake; /** * Begin execution in fake time mode. MUST be paired with a call to * {@link #endFakeTime()} at the end! */ public static synchronized void startFakeTime() { assertNull(oldProvider); oldProvider = Time.getTimeProvider(); fake = new FakeTime(); Time.setTimeProvider(fake); Scheduler.__UNSAFE_reset(new IRunLoop() { @Override public void terminate() { // nothing } @Override public void start() { // nothing } @Override public void add(String tag, EventOutput event, long time) { SharedTimeSecrets.scheduleFakeLoop(fake, event, time); // and discard tag } }); } /** * Exit fake time mode. Returns the JVM to its normal state. */ public static synchronized void endFakeTime() { assertNotNull(oldProvider); Time.setTimeProvider(oldProvider); oldProvider = null; fake = null; } /** * Fast-forward through a certain number of milliseconds. Time will never * move forward in virtualized mode except when this method is called. * * @param millis the number of milliseconds to forward by. * @throws InterruptedException if the current thread is interrupted. */ public static void forward(long millis) throws InterruptedException { fake.forward(millis); } }