FPSClock.java

1
package com.rox.clock;
2
3
import com.rox.time.Sleeper;
4
import com.rox.time.TimeSource;
5
6
import java.util.ArrayList;
7
import java.util.List;
8
9
/**
10
 * A clock which generates {@link Clock} ticket to {@link ClockWatcher}s at the
11
 * specified <cc>hz</cc> in sub second time frame chunks defined by the specified
12
 * <cc>framesPerSecond</cc>
13
 *
14
 * XXX: This cannot deal with fractional FPS such as that of the GameBoy
15
 */
16
public class FPSClock implements Clock, AutoCloseable {
17
    /** Number of clock ticks per second **/
18
    private final long HZ;
19
    /** Number of frames per second at the user level */
20
    private final int FPS;
21
    /** The size of a frame in nanoseconds */
22
    private final long FRAME_TIME_NS;
23
    /** The number of approximate ticks per frame */
24
    private final long TICKS_PER_FRAME;
25
26
    private final long TICKS_REMAINDER_PER_FRAME;
27
    private final TimeSource timeSource;
28
    private final Sleeper sleeper;
29
30
    /** List of subscribers to this {@link Clock}s <cc>tick()</cc> events **/
31
    private final List<ClockWatcher> listeners = new ArrayList<>();
32
33
    private volatile boolean running = false;
34
35
    //pause()/resume() handshake with run()'s loop - both guarded by pauseLock. pauseRequested is also
36
    //volatile so run() can check it once per frame without taking the lock in the common, unpaused case
37
    private final Object pauseLock = new Object();
38
    private volatile boolean pauseRequested = false;
39
    private boolean parked = false;
40
    /** {@link #prepareToRun()} called and {@link #run()} not yet begun - guarded by pauseLock. */
41
    private boolean runPrepared = false;
42
    /** A {@link #stop()} arrived while {@link #runPrepared} - guarded by pauseLock. */
43
    private boolean runCancelled = false;
44
    /** {@link #run()} is executing - guarded by pauseLock. */
45
    private boolean inRun = false;
46
47
    /** Current total of remainder ticks after rounding */
48
    private long tickRemainderBuffer = 0;
49
50
    public FPSClock(final long hz,
51
                    final int framesPerSecond,
52
                    final TimeSource timeSource,
53
                    final Sleeper sleeper){
54
        HZ = hz;
55
        FPS = framesPerSecond;
56 1 1. <init> : Replaced long division with multiplication → TIMED_OUT
        FRAME_TIME_NS = 1_000_000_000L / FPS;
57 1 1. <init> : Replaced long division with multiplication → KILLED
        TICKS_PER_FRAME = HZ / FPS;
58 1 1. <init> : Replaced long modulus with multiplication → KILLED
        TICKS_REMAINDER_PER_FRAME = HZ % FPS;
59
60
        this.timeSource = timeSource;
61
        this.sleeper = sleeper;
62
    }
63
64
    /**
65
     * Keeps track fo fractional ticks while returning the rounded current set of ticks
66
     *
67
     * XXX this is package private to test but it modifies state (tickRemainderBuffer)
68
     *
69
     * @return the number of ticks this frame
70
     */
71
    long ticksThisFrame(){
72
        long ticks = TICKS_PER_FRAME;
73 1 1. ticksThisFrame : Replaced long addition with subtraction → KILLED
        tickRemainderBuffer += TICKS_REMAINDER_PER_FRAME;
74 2 1. ticksThisFrame : changed conditional boundary → KILLED
2. ticksThisFrame : negated conditional → KILLED
        if (tickRemainderBuffer >= FPS) {
75 1 1. ticksThisFrame : Replaced long addition with subtraction → KILLED
            ticks++;
76 1 1. ticksThisFrame : Replaced long subtraction with addition → KILLED
            tickRemainderBuffer -= FPS;
77
        }
78 1 1. ticksThisFrame : replaced long return with 0 for com/rox/clock/FPSClock::ticksThisFrame → KILLED
        return ticks;
79
    }
80
81
    /**
82
     * Start the execution of this {@link Clock}
83
     */
84
    public void run(){
85
        synchronized (pauseLock){
86 1 1. run : negated conditional → KILLED
            if (running){
87
                throw new IllegalStateException("Clock already running");
88
            }
89
            final boolean cancelled = runCancelled;
90
            runPrepared = false;
91
            runCancelled = false;
92 1 1. run : negated conditional → TIMED_OUT
            if (cancelled){
93
                return;
94
            }
95
            running = true;
96
            inRun = true;
97
        }
98
        try {
99 1 1. run : removed call to com/rox/clock/FPSClock::runLoop → KILLED
            runLoop();
100
        } finally {
101
            //however the loop ended (stop(), an interrupt, a listener throwing), release a pause() or
102
            //stopAndWait() still waiting on it
103
            synchronized (pauseLock){
104
                inRun = false;
105 1 1. run : removed call to com/rox/clock/FPSClock::stop → KILLED
                stop();
106
            }
107
        }
108
    }
109
110
    private void runLoop(){
111
        //anchored to a single fixed reference point (runStartTime), not re-measured fresh each
112
        //frame - Thread.sleep() (via Sleeper) routinely oversleeps its requested duration by tens to
113
        //hundreds of microseconds (OS scheduler granularity), and a fresh-each-frame measurement
114
        //never recovers that lost time, so it accumulates: ~10ms/s of real-time drift measured
115
        //empirically, enough to exhaust a 200ms audio buffer margin in about 20 seconds. Anchoring
116
        //each frame's deadline to runStartTime + frameIndex*FRAME_TIME_NS means an oversleep on one
117
        //frame simply shortens (or skips) the next frame's sleep, so the schedule self-corrects
118
        //instead of drifting indefinitely.
119
        long runStartTime = timeSource.nanoTime();
120
        long frameIndex = 0;
121
122 1 1. runLoop : negated conditional → KILLED
        while (running) {
123
            //XXX This could be wrapped in a executeWithinFrame(()->{})
124 1 1. runLoop : removed call to com/rox/clock/FPSClock::runFrame → TIMED_OUT
            runFrame();
125
            try {
126 1 1. runLoop : negated conditional → TIMED_OUT
                if (parkWhilePaused()){
127
                    //however long the pause lasted, it isn't time the schedule should try to catch up
128
                    //on - re-anchor rather than racing through a burst of unthrottled frames
129
                    runStartTime = timeSource.nanoTime();
130
                    frameIndex = 0;
131
                    continue;
132
                }
133 3 1. runLoop : removed call to com/rox/clock/FPSClock::throttle → TIMED_OUT
2. runLoop : Replaced long addition with subtraction → KILLED
3. runLoop : Replaced long multiplication with division → KILLED
                throttle(runStartTime + frameIndex * FRAME_TIME_NS);
134
            } catch (InterruptedException e) {
135 1 1. runLoop : removed call to java/io/PrintStream::println → SURVIVED
                /* LOG */System.out.println("Encountered issues using Thread.sleep(), terminating clock!");
136
                running = false;
137
            }
138 1 1. runLoop : Replaced long addition with subtraction → KILLED
            frameIndex++;
139
        }
140
    }
141
142
    /**
143
     * Parks the {@link #run()} loop (between frames, never mid-frame) for as long as a {@link #pause()}
144
     * is in effect.
145
     *
146
     * @return true if it parked at all
147
     */
148
    private boolean parkWhilePaused() throws InterruptedException {
149 1 1. parkWhilePaused : negated conditional → TIMED_OUT
        if (!pauseRequested){
150 1 1. parkWhilePaused : replaced boolean return with true for com/rox/clock/FPSClock::parkWhilePaused → TIMED_OUT
            return false;
151
        }
152
        synchronized (pauseLock){
153
            parked = true;
154 1 1. parkWhilePaused : removed call to java/lang/Object::notifyAll → TIMED_OUT
            pauseLock.notifyAll(); //release pause()'s wait for this loop to genuinely stop ticking
155
            try {
156
                //no separate running check needed: stop() clears pauseRequested under this same lock
157 1 1. parkWhilePaused : negated conditional → TIMED_OUT
                while (pauseRequested){
158 1 1. parkWhilePaused : removed call to java/lang/Object::wait → TIMED_OUT
                    pauseLock.wait();
159
                }
160
            } finally {
161
                parked = false;
162
            }
163
        }
164 1 1. parkWhilePaused : replaced boolean return with false for com/rox/clock/FPSClock::parkWhilePaused → KILLED
        return true;
165
    }
166
167
    /**
168
     * Execute all <cc>tick()</cc>s in this frame
169
     */
170
    void runFrame() {
171 1 1. runFrame : removed call to com/rox/clock/FPSClock::tick → TIMED_OUT
        tick(ticksThisFrame());
172
    }
173
174
    /**
175
     * Slow the rate of generating tickets by consuming the rest of the frame
176
     *
177
     * @param frameStartTime used to calculate when the frame is expected to end.
178
     */
179
    void throttle(final long frameStartTime) throws InterruptedException {
180 1 1. throttle : Replaced long subtraction with addition → KILLED
        long elapsedSinceFrameStart = timeSource.nanoTime() - frameStartTime;
181 1 1. throttle : Replaced long subtraction with addition → KILLED
        long timeRemainingInFrame = FRAME_TIME_NS - elapsedSinceFrameStart;
182
183 2 1. throttle : changed conditional boundary → SURVIVED
2. throttle : negated conditional → KILLED
        if (timeRemainingInFrame > 0) {
184
185
            //XXX Do we want to just throw the exception here?
186 1 1. throttle : removed call to com/rox/time/Sleeper::sleepFor → KILLED
            sleeper.sleepFor(timeRemainingInFrame);
187
        }
188
    }
189
190
    /**
191
     * Stop the execution of this {@link Clock}
192
     */
193
    public void stop(){
194
        synchronized (pauseLock){
195
            //inside the lock: run() checks for a cancel and sets running under it too
196
            running = false;
197
            runCancelled = runPrepared;
198
            //a stale request would otherwise park a later run() straight away with nobody to resume it
199
            pauseRequested = false;
200 1 1. stop : removed call to java/lang/Object::notifyAll → TIMED_OUT
            pauseLock.notifyAll(); //release a parked run() loop, and a pause() still waiting on one
201
        }
202
    }
203
204
    /**
205
     * {@link #stop()}, then blocks until {@link #run()} has returned, so nothing ticks after - waiting out
206
     * interrupts, like {@link #pause()}. Never call it from a {@link ClockWatcher}: that's {@code run()}'s own thread.
207
     */
208
    @Override
209
    public void stopAndWait(){
210
        boolean interrupted = false;
211
        synchronized (pauseLock){
212 1 1. stopAndWait : removed call to com/rox/clock/FPSClock::stop → TIMED_OUT
            stop();
213 1 1. stopAndWait : negated conditional → TIMED_OUT
            while (inRun){
214
                try {
215 1 1. stopAndWait : removed call to java/lang/Object::wait → TIMED_OUT
                    pauseLock.wait();
216
                } catch (InterruptedException e){
217
                    interrupted = true;
218
                }
219
            }
220
        }
221 1 1. stopAndWait : negated conditional → KILLED
        if (interrupted){
222 1 1. stopAndWait : removed call to java/lang/Thread::interrupt → KILLED
            Thread.currentThread().interrupt();
223
        }
224
    }
225
226
    @Override
227
    public void prepareToRun(){
228
        synchronized (pauseLock){
229
            runPrepared = true;
230
            runCancelled = false;
231
        }
232
    }
233
234
    /**
235
     * Freezes {@link #run()} at the end of its current frame (up to one frame's worth of ticks away),
236
     * blocking until it's genuinely parked. Like {@code NES.powerOn()}, waits out interrupts rather
237
     * than returning early - the caller relies on a {@code true} meaning nothing else is ticking.
238
     */
239
    @Override
240
    public boolean pause(){
241
        boolean interrupted = false;
242
        final boolean paused;
243
        synchronized (pauseLock){
244 1 1. pause : negated conditional → TIMED_OUT
            if (running){
245
                pauseRequested = true;
246
            }
247 2 1. pause : negated conditional → TIMED_OUT
2. pause : negated conditional → KILLED
            while (pauseRequested && !parked){
248
                try {
249 1 1. pause : removed call to java/lang/Object::wait → TIMED_OUT
                    pauseLock.wait();
250
                } catch (InterruptedException e){
251
                    interrupted = true;
252
                }
253
            }
254
            paused = parked;
255
        }
256 1 1. pause : negated conditional → KILLED
        if (interrupted){
257 1 1. pause : removed call to java/lang/Thread::interrupt → KILLED
            Thread.currentThread().interrupt();
258
        }
259 2 1. pause : replaced boolean return with true for com/rox/clock/FPSClock::pause → KILLED
2. pause : replaced boolean return with false for com/rox/clock/FPSClock::pause → KILLED
        return paused;
260
    }
261
262
    @Override
263
    public void resume(){
264
        synchronized (pauseLock){
265
            pauseRequested = false;
266 1 1. resume : removed call to java/lang/Object::notifyAll → TIMED_OUT
            pauseLock.notifyAll();
267
        }
268
    }
269
270
    public boolean isRunning(){
271 2 1. isRunning : replaced boolean return with false for com/rox/clock/FPSClock::isRunning → TIMED_OUT
2. isRunning : replaced boolean return with true for com/rox/clock/FPSClock::isRunning → KILLED
        return running;
272
    }
273
274
    public void addListener(final ClockWatcher listener){
275
        this.listeners.add(listener);
276
    }
277
278
    public void removeListener(final ClockWatcher listener){
279
        this.listeners.remove(listener);
280
    }
281
282
    public void tick(final long count){
283 3 1. tick : negated conditional → TIMED_OUT
2. tick : Replaced long addition with subtraction → TIMED_OUT
3. tick : changed conditional boundary → KILLED
        for (long i = 0; i < count; i++){
284 1 1. tick : removed call to com/rox/clock/FPSClock::tick → TIMED_OUT
            tick();
285
        }
286
    }
287
288
    public void tick(){
289 1 1. tick : removed call to java/util/List::forEach → TIMED_OUT
        listeners.forEach(ClockWatcher::tick);
290
    }
291
292
    public int listeners(){
293 1 1. listeners : replaced int return with 0 for com/rox/clock/FPSClock::listeners → KILLED
        return listeners.size();
294
    }
295
296
    @Override
297
    public void close() throws Exception {
298 1 1. close : removed call to com/rox/clock/FPSClock::stop → SURVIVED
        stop();
299
    }
300
}

Mutations

56

1.1
Location : <init>
Killed by : none
Replaced long division with multiplication → TIMED_OUT

57

1.1
Location : <init>
Killed by : com.rox.clock.FPSClockTest.[engine:junit-jupiter]/[class:com.rox.clock.FPSClockTest]/[method:carriesFractionalTicksAcrossFrames()]
Replaced long division with multiplication → KILLED

58

1.1
Location : <init>
Killed by : com.rox.clock.FPSClockTest.[engine:junit-jupiter]/[class:com.rox.clock.FPSClockTest]/[method:carriesFractionalTicksAcrossFrames()]
Replaced long modulus with multiplication → KILLED

73

1.1
Location : ticksThisFrame
Killed by : com.rox.clock.FPSClockTest.[engine:junit-jupiter]/[class:com.rox.clock.FPSClockTest]/[method:carriesFractionalTicksAcrossFrames()]
Replaced long addition with subtraction → KILLED

74

1.1
Location : ticksThisFrame
Killed by : com.rox.clock.FPSClockTest.[engine:junit-jupiter]/[class:com.rox.clock.FPSClockTest]/[method:carriesFractionalTicksAcrossFrames()]
changed conditional boundary → KILLED

2.2
Location : ticksThisFrame
Killed by : com.rox.clock.FPSClockTest.[engine:junit-jupiter]/[class:com.rox.clock.FPSClockTest]/[method:carriesFractionalTicksAcrossFrames()]
negated conditional → KILLED

75

1.1
Location : ticksThisFrame
Killed by : com.rox.clock.FPSClockTest.[engine:junit-jupiter]/[class:com.rox.clock.FPSClockTest]/[method:carriesFractionalTicksAcrossFrames()]
Replaced long addition with subtraction → KILLED

76

1.1
Location : ticksThisFrame
Killed by : com.rox.clock.FPSClockTest.[engine:junit-jupiter]/[class:com.rox.clock.FPSClockTest]/[test-template:realWorldExamples(java.lang.String, int, long)]/[test-template-invocation:#2]
Replaced long subtraction with addition → KILLED

78

1.1
Location : ticksThisFrame
Killed by : com.rox.clock.FPSClockTest.[engine:junit-jupiter]/[class:com.rox.clock.FPSClockTest]/[method:carriesFractionalTicksAcrossFrames()]
replaced long return with 0 for com/rox/clock/FPSClock::ticksThisFrame → KILLED

86

1.1
Location : run
Killed by : com.rox.clock.FPSClockTest.[engine:junit-jupiter]/[class:com.rox.clock.FPSClockTest]/[method:stopAndWaitAfterPrepareToRunCancelsTheRunWithoutWaitingForIt()]
negated conditional → KILLED

92

1.1
Location : run
Killed by : none
negated conditional → TIMED_OUT

99

1.1
Location : run
Killed by : com.rox.clock.FPSClockTest.[engine:junit-jupiter]/[class:com.rox.clock.FPSClockTest]/[method:aListenerThrowingStillEndsTheRunCleanly()]
removed call to com/rox/clock/FPSClock::runLoop → KILLED

105

1.1
Location : run
Killed by : com.rox.clock.FPSClockTest.[engine:junit-jupiter]/[class:com.rox.clock.FPSClockTest]/[method:aListenerThrowingStillEndsTheRunCleanly()]
removed call to com/rox/clock/FPSClock::stop → KILLED

122

1.1
Location : runLoop
Killed by : com.rox.clock.FPSClockTest.[engine:junit-jupiter]/[class:com.rox.clock.FPSClockTest]/[method:aListenerThrowingStillEndsTheRunCleanly()]
negated conditional → KILLED

124

1.1
Location : runLoop
Killed by : none
removed call to com/rox/clock/FPSClock::runFrame → TIMED_OUT

126

1.1
Location : runLoop
Killed by : none
negated conditional → TIMED_OUT

133

1.1
Location : runLoop
Killed by : com.rox.clock.FPSClockTest.[engine:junit-jupiter]/[class:com.rox.clock.FPSClockTest]/[method:runAnchorsEachFramesDeadlineToAFixedStartSoOneFramesOversleepShortensTheNextFramesSleep()]
Replaced long addition with subtraction → KILLED

2.2
Location : runLoop
Killed by : com.rox.clock.FPSClockTest.[engine:junit-jupiter]/[class:com.rox.clock.FPSClockTest]/[method:runAnchorsEachFramesDeadlineToAFixedStartSoOneFramesOversleepShortensTheNextFramesSleep()]
Replaced long multiplication with division → KILLED

3.3
Location : runLoop
Killed by : none
removed call to com/rox/clock/FPSClock::throttle → TIMED_OUT

135

1.1
Location : runLoop
Killed by : none
removed call to java/io/PrintStream::println → SURVIVED
Covering tests

138

1.1
Location : runLoop
Killed by : com.rox.clock.FPSClockTest.[engine:junit-jupiter]/[class:com.rox.clock.FPSClockTest]/[method:runAnchorsEachFramesDeadlineToAFixedStartSoOneFramesOversleepShortensTheNextFramesSleep()]
Replaced long addition with subtraction → KILLED

149

1.1
Location : parkWhilePaused
Killed by : none
negated conditional → TIMED_OUT

150

1.1
Location : parkWhilePaused
Killed by : none
replaced boolean return with true for com/rox/clock/FPSClock::parkWhilePaused → TIMED_OUT

154

1.1
Location : parkWhilePaused
Killed by : none
removed call to java/lang/Object::notifyAll → TIMED_OUT

157

1.1
Location : parkWhilePaused
Killed by : none
negated conditional → TIMED_OUT

158

1.1
Location : parkWhilePaused
Killed by : none
removed call to java/lang/Object::wait → TIMED_OUT

164

1.1
Location : parkWhilePaused
Killed by : com.rox.clock.FPSClockTest.[engine:junit-jupiter]/[class:com.rox.clock.FPSClockTest]/[method:resumeReAnchorsTheScheduleInsteadOfCatchingUpOnThePausedTime()]
replaced boolean return with false for com/rox/clock/FPSClock::parkWhilePaused → KILLED

171

1.1
Location : runFrame
Killed by : none
removed call to com/rox/clock/FPSClock::tick → TIMED_OUT

180

1.1
Location : throttle
Killed by : com.rox.clock.FPSClockTest.[engine:junit-jupiter]/[class:com.rox.clock.FPSClockTest]/[method:resumeReAnchorsTheScheduleInsteadOfCatchingUpOnThePausedTime()]
Replaced long subtraction with addition → KILLED

181

1.1
Location : throttle
Killed by : com.rox.clock.FPSClockTest.[engine:junit-jupiter]/[class:com.rox.clock.FPSClockTest]/[method:doesNotSleepWhenFrameAlreadyExceeded()]
Replaced long subtraction with addition → KILLED

183

1.1
Location : throttle
Killed by : none
changed conditional boundary → SURVIVED
Covering tests

2.2
Location : throttle
Killed by : com.rox.clock.FPSClockTest.[engine:junit-jupiter]/[class:com.rox.clock.FPSClockTest]/[method:doesNotSleepWhenFrameAlreadyExceeded()]
negated conditional → KILLED

186

1.1
Location : throttle
Killed by : com.rox.clock.FPSClockTest.[engine:junit-jupiter]/[class:com.rox.clock.FPSClockTest]/[method:sleepsForRemainingFrameTime()]
removed call to com/rox/time/Sleeper::sleepFor → KILLED

200

1.1
Location : stop
Killed by : none
removed call to java/lang/Object::notifyAll → TIMED_OUT

212

1.1
Location : stopAndWait
Killed by : none
removed call to com/rox/clock/FPSClock::stop → TIMED_OUT

213

1.1
Location : stopAndWait
Killed by : none
negated conditional → TIMED_OUT

215

1.1
Location : stopAndWait
Killed by : none
removed call to java/lang/Object::wait → TIMED_OUT

221

1.1
Location : stopAndWait
Killed by : com.rox.clock.FPSClockTest.[engine:junit-jupiter]/[class:com.rox.clock.FPSClockTest]/[method:stopAndWaitWaitsOutAnInterrupt()]
negated conditional → KILLED

222

1.1
Location : stopAndWait
Killed by : com.rox.clock.FPSClockTest.[engine:junit-jupiter]/[class:com.rox.clock.FPSClockTest]/[method:stopAndWaitWaitsOutAnInterrupt()]
removed call to java/lang/Thread::interrupt → KILLED

244

1.1
Location : pause
Killed by : none
negated conditional → TIMED_OUT

247

1.1
Location : pause
Killed by : none
negated conditional → TIMED_OUT

2.2
Location : pause
Killed by : com.rox.clock.FPSClockTest.[engine:junit-jupiter]/[class:com.rox.clock.FPSClockTest]/[method:pauseWhileAlreadyPausedReturnsTrueStraightAway()]
negated conditional → KILLED

249

1.1
Location : pause
Killed by : none
removed call to java/lang/Object::wait → TIMED_OUT

256

1.1
Location : pause
Killed by : com.rox.clock.FPSClockTest.[engine:junit-jupiter]/[class:com.rox.clock.FPSClockTest]/[method:pauseWhileAlreadyPausedReturnsTrueStraightAway()]
negated conditional → KILLED

257

1.1
Location : pause
Killed by : com.rox.clock.FPSClockTest.[engine:junit-jupiter]/[class:com.rox.clock.FPSClockTest]/[method:pauseWaitsOutAnInterruptRatherThanReturningBeforeTheLoopHasParked()]
removed call to java/lang/Thread::interrupt → KILLED

259

1.1
Location : pause
Killed by : com.rox.clock.FPSClockTest.[engine:junit-jupiter]/[class:com.rox.clock.FPSClockTest]/[method:pauseReturnsFalseWhenTheClockIsNotRunning()]
replaced boolean return with true for com/rox/clock/FPSClock::pause → KILLED

2.2
Location : pause
Killed by : com.rox.clock.FPSClockTest.[engine:junit-jupiter]/[class:com.rox.clock.FPSClockTest]/[method:pauseWhileAlreadyPausedReturnsTrueStraightAway()]
replaced boolean return with false for com/rox/clock/FPSClock::pause → KILLED

266

1.1
Location : resume
Killed by : none
removed call to java/lang/Object::notifyAll → TIMED_OUT

271

1.1
Location : isRunning
Killed by : com.rox.clock.FPSClockTest.[engine:junit-jupiter]/[class:com.rox.clock.FPSClockTest]/[method:resumeWhenNotPausedIsHarmless()]
replaced boolean return with true for com/rox/clock/FPSClock::isRunning → KILLED

2.2
Location : isRunning
Killed by : none
replaced boolean return with false for com/rox/clock/FPSClock::isRunning → TIMED_OUT

283

1.1
Location : tick
Killed by : none
negated conditional → TIMED_OUT

2.2
Location : tick
Killed by : com.rox.clock.FPSClockTest.[engine:junit-jupiter]/[class:com.rox.clock.FPSClockTest]/[method:resumeReAnchorsTheScheduleInsteadOfCatchingUpOnThePausedTime()]
changed conditional boundary → KILLED

3.3
Location : tick
Killed by : none
Replaced long addition with subtraction → TIMED_OUT

284

1.1
Location : tick
Killed by : none
removed call to com/rox/clock/FPSClock::tick → TIMED_OUT

289

1.1
Location : tick
Killed by : none
removed call to java/util/List::forEach → TIMED_OUT

293

1.1
Location : listeners
Killed by : com.rox.clock.FPSClockTest.[engine:junit-jupiter]/[class:com.rox.clock.FPSClockTest]/[method:addListener()]
replaced int return with 0 for com/rox/clock/FPSClock::listeners → KILLED

298

1.1
Location : close
Killed by : none
removed call to com/rox/clock/FPSClock::stop → SURVIVED
Covering tests

Active mutators

Tests examined


Report generated by PIT 1.22.1