Skip to content

Instantly share code, notes, and snippets.

@daveneedstoknow
Last active April 20, 2016 13:38
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save daveneedstoknow/4cbb6a7d707d8efe4cb5fff1ee748923 to your computer and use it in GitHub Desktop.
Save daveneedstoknow/4cbb6a7d707d8efe4cb5fff1ee748923 to your computer and use it in GitHub Desktop.
Roulette Kata
import java.util.Random;
public class RouletteWheel {
private boolean spinning = false;
private final WheelObserver wheelObserver;
private long spinForMs;
private long currentMs = 0;
private final Random random = new Random();
public static void spin(final WheelObserver wheelObserver, final int spinDuration) {
RouletteWheel rouletteWheel = new RouletteWheel(wheelObserver);
TickProvider tickProvider = new TickProvider(rouletteWheel);
tickProvider.start();
rouletteWheel.spin(spinDuration);
}
RouletteWheel(final WheelObserver wheelObserver) {
this.wheelObserver = wheelObserver;
}
void spin(final long spinForMs) {
this.spinning = true;
this.spinForMs = spinForMs;
}
void tick(final long timeMs) {
currentMs = timeMs;
if (spinning && currentMs >= spinForMs)
{
spinning = false;
final int location = random.nextInt(37);
this.wheelObserver.stopped(location);
}
}
}
import org.junit.*;
import static org.junit.Assert.*;
import static org.mockito.Mockito.*;
import java.util.Set;
import java.util.HashSet;
public class RouletteWheelTest {
@Test
public void shouldNotifyStopped20SecondsAfterSpin() {
WheelObserver wheelObserver = mock(WheelObserver.class);
RouletteWheel wheel = new RouletteWheel(wheelObserver);
wheel.spin(20000);
wheel.tick(20000);
verify(wheelObserver).stopped(anyInt());
}
@Test
public void shouldProvideRandomBallLocationWhenStopped() {
final boolean seenAll[] = new boolean[1];
seenAll[0] = false;
WheelObserver wheelObserver = new WheelObserver() {
Set<Integer> seen = new HashSet<Integer>();
public void stopped(final int location) {
if (location < 0 || location > 36)
throw new IllegalArgumentException();
seen.add(location);
if (seen.size() == 37) seenAll[0] = true;
}
};
RouletteWheel wheel = new RouletteWheel(wheelObserver);
for (int x = 0; x < 1000; x++)
{
wheel.spin(0);
wheel.tick(20000);
}
assertTrue(seenAll[0]);
}
@Test
public void shouldSpecifyBallLocationWhenStopped() {
WheelObserver wheelObserver = mock(WheelObserver.class);
RouletteWheel wheel = new RouletteWheel(wheelObserver);
long spinFor20s = 20000;
wheel.spin(spinFor20s);
wheel.tick(20000);
verify(wheelObserver, times(1)).stopped(anyInt());
}
@Test
public void shouldSpecifyBallLocationOnceWhenStopped() {
WheelObserver wheelObserver = mock(WheelObserver.class);
RouletteWheel wheel = new RouletteWheel(wheelObserver);
long spinFor20s = 20000;
wheel.spin(spinFor20s);
wheel.tick(20000);
wheel.tick(20001);
verify(wheelObserver, times(1)).stopped(anyInt());
}
@Test
public void shouldNotNotifyStoppedBeforeSpinEnd() {
WheelObserver wheelObserver = mock(WheelObserver.class);
RouletteWheel wheel = new RouletteWheel(wheelObserver);
long spinFor20s = 20000;
wheel.spin(spinFor20s);
long timeEndMs = 10000;
wheel.tick(timeEndMs);
verify(wheelObserver, never() ).stopped(anyInt());
}
@Test
public void shouldBuildGame() {
WheelObserver wheelObserver = mock(WheelObserver.class);
long now= System.currentTimeMillis();
RouletteWheel.spin(wheelObserver, 500);
verify(wheelObserver, timeout(600).times(1)).stopped(anyInt());
long elapsed = System.currentTimeMillis() - now;
assertTrue(elapsed > 480);
assertTrue(elapsed < 520);
}
}
import java.util.Timer;
import java.util.TimerTask;
class TickProvider {
private final TimerTask tickTask;
TickProvider(final RouletteWheel rouletteWheel)
{
this.tickTask = new TimerTask() {
private long startMs = System.currentTimeMillis();
public void run() {
rouletteWheel.tick(System.currentTimeMillis() - startMs);
}
};
}
void start() {
Timer timer = new Timer();
timer.schedule(tickTask,0, 100);
}
}
import org.junit.*;
import static org.junit.Assert.*;
import static org.mockito.Mockito.*;
import static org.mockito.AdditionalMatchers.*;
import org.mockito.InOrder;
public class TickProviderTest {
@Test
public void shouldNotifyTickWhenStarted() {
RouletteWheel rouletteWheel = mock(RouletteWheel.class);
TickProvider tickProvider = new TickProvider(rouletteWheel);
tickProvider.start();
verify(rouletteWheel, timeout(150).atLeastOnce()).tick(anyInt());
}
@Test
public void shouldNotifyTickEvery100ms() throws Exception {
RouletteWheel rouletteWheel = mock(RouletteWheel.class);
TickProvider tickProvider = new TickProvider(rouletteWheel);
tickProvider.start();
verify(rouletteWheel, timeout(500).atLeast(5)).tick(anyInt());
}
@Test
public void shouldIncrementEachTickByApprox100() throws Exception {
RouletteWheel rouletteWheel = mock(RouletteWheel.class);
TickProvider tickProvider = new TickProvider(rouletteWheel);
InOrder inOrder = inOrder(rouletteWheel,
rouletteWheel,
rouletteWheel);
tickProvider.start();
Thread.sleep(200);
inOrder.verify(rouletteWheel)
.tick(and(gt((long)0), lt((long)20)));
inOrder.verify(rouletteWheel)
.tick(and(gt((long)90), lt((long)120)));
inOrder.verify(rouletteWheel)
.tick(and(gt((long)190), lt((long)220)));
}
}
@daveneedstoknow
Copy link
Author

@daveneedstoknow
Copy link
Author

You can see my working here (up to revision 106) http://www.cyber-dojo.org/review/show/92E37F

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment