LockObserveList implementation, tests for Lock and List
This commit is contained in:
@@ -6,6 +6,8 @@ package mc.core;
|
|||||||
|
|
||||||
import lombok.AllArgsConstructor;
|
import lombok.AllArgsConstructor;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
import mc.core.world.Chunk;
|
||||||
|
import sun.reflect.generics.reflectiveObjects.NotImplementedException;
|
||||||
|
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
|
|
||||||
@@ -14,6 +16,10 @@ import java.io.Serializable;
|
|||||||
public class Location implements Serializable {
|
public class Location implements Serializable {
|
||||||
private double x, y, z;
|
private double x, y, z;
|
||||||
|
|
||||||
|
public Location(long compactValue) {
|
||||||
|
set(compactValue);
|
||||||
|
}
|
||||||
|
|
||||||
private static int floor_double(double value) {
|
private static int floor_double(double value) {
|
||||||
int i = (int) value;
|
int i = (int) value;
|
||||||
return value < (double) i ? i - 1 : i;
|
return value < (double) i ? i - 1 : i;
|
||||||
@@ -31,10 +37,6 @@ public class Location implements Serializable{
|
|||||||
return new Location(0, 10, 0);
|
return new Location(0, 10, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Location(long compactValue) {
|
|
||||||
set(compactValue);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void set(Location location) {
|
public void set(Location location) {
|
||||||
this.x = location.x;
|
this.x = location.x;
|
||||||
this.y = location.y;
|
this.y = location.y;
|
||||||
@@ -55,6 +57,11 @@ public class Location implements Serializable{
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Chunk getChunk() {
|
||||||
|
// TODO: Implement
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
public int getBlockX() {
|
public int getBlockX() {
|
||||||
return (int) x;
|
return (int) x;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,44 @@
|
|||||||
|
package mc.core.events.lock;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
|
public class LockObserveList implements Consumer<PoorMansLock> {
|
||||||
|
private List<PoorMansLock> locks = new ArrayList<>();
|
||||||
|
private Runnable callback;
|
||||||
|
|
||||||
|
public void setCallback(Runnable callback) {
|
||||||
|
this.callback = callback;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void add(PoorMansLock lock) {
|
||||||
|
locks.add(lock);
|
||||||
|
lock.addCallback(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void release() {
|
||||||
|
for (PoorMansLock lock : locks) {
|
||||||
|
lock.removeCallback(this);
|
||||||
|
}
|
||||||
|
locks.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isReady() {
|
||||||
|
for (PoorMansLock lock : locks) {
|
||||||
|
if (lock.isLocked())
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void accept(PoorMansLock lock) {
|
||||||
|
if (!lock.isLocked()) {
|
||||||
|
if (isReady()) {
|
||||||
|
if (callback != null)
|
||||||
|
callback.run();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
90
event-loop/src/test/java/mc/core/events/LockTest.java
Normal file
90
event-loop/src/test/java/mc/core/events/LockTest.java
Normal file
@@ -0,0 +1,90 @@
|
|||||||
|
package mc.core.events;
|
||||||
|
|
||||||
|
import mc.core.events.lock.LockObserveList;
|
||||||
|
import mc.core.events.lock.PoorMansLock;
|
||||||
|
import org.junit.Assert;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import java.util.concurrent.CountDownLatch;
|
||||||
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
|
|
||||||
|
public class LockTest {
|
||||||
|
@Test
|
||||||
|
public void basicTest() throws InterruptedException {
|
||||||
|
AtomicBoolean engageCallbackCalled = new AtomicBoolean(false);
|
||||||
|
AtomicBoolean disengageCallbackCalled = new AtomicBoolean(false);
|
||||||
|
|
||||||
|
PoorMansLock lock = new PoorMansLock();
|
||||||
|
lock.addCallback(lock1 -> {
|
||||||
|
if (lock1.isLocked())
|
||||||
|
engageCallbackCalled.set(true);
|
||||||
|
else
|
||||||
|
disengageCallbackCalled.set(true);
|
||||||
|
});
|
||||||
|
lock.lock();
|
||||||
|
Assert.assertTrue("Lock is not locked", lock.isLocked());
|
||||||
|
Assert.assertTrue("Engage callback was not called", engageCallbackCalled.get());
|
||||||
|
|
||||||
|
engageCallbackCalled.set(false);
|
||||||
|
try {
|
||||||
|
lock.lock();
|
||||||
|
Assert.assertFalse("Engage callback was called from attempt to block from the same thread", engageCallbackCalled.get());
|
||||||
|
} catch (Exception ex) {
|
||||||
|
Assert.fail("Exception fired while attempting to lock from the same thread");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Assert.assertFalse("Disengage callback was called while not actually disengaging [x1]", disengageCallbackCalled.get());
|
||||||
|
|
||||||
|
AtomicBoolean lockExceptionFired = new AtomicBoolean(false);
|
||||||
|
AtomicBoolean unlockExceptionFired = new AtomicBoolean(false);
|
||||||
|
CountDownLatch latch = new CountDownLatch(1);
|
||||||
|
new Thread(() -> {
|
||||||
|
try {
|
||||||
|
lock.lock();
|
||||||
|
} catch (Exception ex) {
|
||||||
|
lockExceptionFired.set(true);
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
lock.unlock();
|
||||||
|
} catch (Exception ex) {
|
||||||
|
unlockExceptionFired.set(true);
|
||||||
|
}
|
||||||
|
latch.countDown();
|
||||||
|
}).start();
|
||||||
|
|
||||||
|
latch.await();
|
||||||
|
Assert.assertTrue("Exception was not fired on concurrent lock attempt", lockExceptionFired.get());
|
||||||
|
Assert.assertTrue("Exception was not fired on non-owner unlock attempt", unlockExceptionFired.get());
|
||||||
|
Assert.assertFalse("Disengage callback was called while not actually disengaging [x2]", disengageCallbackCalled.get());
|
||||||
|
|
||||||
|
lock.unlock();
|
||||||
|
Assert.assertTrue("Disengage callback was on called on lock disengage", disengageCallbackCalled.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void observeListTest() {
|
||||||
|
PoorMansLock lock1 = new PoorMansLock();
|
||||||
|
PoorMansLock lock2 = new PoorMansLock();
|
||||||
|
|
||||||
|
LockObserveList list = new LockObserveList();
|
||||||
|
list.add(lock1);
|
||||||
|
list.add(lock2);
|
||||||
|
|
||||||
|
Assert.assertTrue("LockObserveList was no able to correctly identify lock states for unlocked locks", list.isReady());
|
||||||
|
lock1.lock();
|
||||||
|
Assert.assertFalse("LockObserveList was no able to correctly identify lock states for list with one locked lock", list.isReady());
|
||||||
|
|
||||||
|
|
||||||
|
AtomicBoolean listReadyCallbackCalled = new AtomicBoolean(false);
|
||||||
|
list.setCallback(() -> listReadyCallbackCalled.set(true));
|
||||||
|
lock2.lock();
|
||||||
|
|
||||||
|
Assert.assertFalse("Callback was called when another lock got engaged", listReadyCallbackCalled.get());
|
||||||
|
lock1.unlock();
|
||||||
|
Assert.assertFalse("Callback was called while one lock is still locked", listReadyCallbackCalled.get());
|
||||||
|
lock2.unlock();
|
||||||
|
Assert.assertTrue("Callback was not called when both locks are actually free", listReadyCallbackCalled.get());
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user