package rabbitescape.engine.logic; import static org.hamcrest.CoreMatchers.*; import static org.hamcrest.MatcherAssert.*; import org.junit.*; import rabbitescape.engine.Block; import rabbitescape.engine.Direction; import rabbitescape.engine.Rabbit; import rabbitescape.engine.Block.Shape; import rabbitescape.engine.Token; import rabbitescape.engine.World; import rabbitescape.engine.textworld.TextWorldManip; public class TestWorldChanges { class AddTokens implements Runnable { private final World world; public AddTokens( World world ) { this.world = world; } @Override public void run() { for ( int i = 0; i < 100; ++i ) { world.changes.addToken( 3, 0, Token.Type.bash ); } } } class StepAlot implements Runnable { private final World world; private boolean running; public StepAlot( World world ) { this.world = world; this.running = true; } @Override public void run() { while( running ) { world.step(); } } public void pleaseStop() { running = false; } } @Test public void Simultaneous_changes_all_register() throws Exception { final World world = TextWorldManip.createWorld( " ", " ", " r ", "####" ); world.abilities.put( Token.Type.bash, 201 ); // This is what we're testing: add tokens in 2 simultaneous threads Thread t1 = new Thread( new AddTokens( world ) ); Thread t2 = new Thread( new AddTokens( world ) ); StepAlot stepalot = new StepAlot( world ); Thread t3 = new Thread( stepalot ); t1.start(); t2.start(); t3.start(); t1.join(); t2.join(); stepalot.pleaseStop(); t3.join(); // There should have been no concurrent modification problems // Last step to make sure we have registered all changes world.step(); // All 200 adds should have worked assertThat( world.abilities.get( Token.Type.bash ), equalTo( 1 ) ); assertThat( world.things.size(), equalTo( 200 ) ); } @Test public void Changes_can_be_reverted() { String[] worldText = new String[] { ":name=My Round X", ":description=Go and\nreturn", ":author_name=dave", ":author_url=", ":hint.1=", ":hint.2=", ":hint.3=", ":num_rabbits=25", ":num_to_save=4", ":rabbit_delay=2", ":num_saved=5", ":num_killed=4", ":num_waiting=16", ":rabbit_index_count=5", ":paused=false", ":bash=1", ":bridge=3", ":dig=2", "#####", "#i #", "# **#", "#####", ":*=r{index:2}", ":*=r{index:4}" }; World world = TextWorldManip.createWorld( worldText ); Token tok0 = world.getTokenAt( 1, 1 ); Rabbit rabbit0 = world.rabbits.get( 0 ); Rabbit rabbit1 = world.rabbits.get( 1 ); // One of every type of change world.changes.enterRabbit( new Rabbit( 1, 2, Direction.RIGHT ) ); world.changes.killRabbit( rabbit0 ); world.changes.saveRabbit( rabbit1 ); world.changes.addToken( 2, 1, Token.Type.bash ); world.changes.removeToken( tok0 ); world.changes.addBlock( new Block( 1, 1, Block.Material.EARTH, Shape.FLAT, 0 ) ); world.changes.removeBlockAt( 0, 0 ); // This is what we are testing - revert the changes world.changes.revert(); assertThat( TextWorldManip.renderCompleteWorld( world, true ), equalTo( worldText ) ); // They should have no effect, even if you apply them world.changes.apply(); assertThat( TextWorldManip.renderCompleteWorld( world, true ), equalTo( worldText ) ); } }