143 lines
5.4 KiB
Java
143 lines
5.4 KiB
Java
package games.dmg.spigotquestboard;
|
|
|
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
|
import static org.junit.jupiter.api.Assertions.assertFalse;
|
|
import static org.junit.jupiter.api.Assertions.assertThrows;
|
|
import static org.junit.jupiter.api.Assertions.assertTrue;
|
|
import static org.mockito.ArgumentMatchers.contains;
|
|
import static org.mockito.Mockito.mock;
|
|
import static org.mockito.Mockito.never;
|
|
import static org.mockito.Mockito.verify;
|
|
|
|
import java.io.IOException;
|
|
import java.time.Instant;
|
|
import java.util.List;
|
|
import java.util.UUID;
|
|
import org.bukkit.entity.Player;
|
|
import org.junit.jupiter.api.Test;
|
|
|
|
final class QuestCompletionControllerTest {
|
|
@Test
|
|
void removesExactDeliverySettlesRewardReportsOverflowAndNotifies() throws Exception {
|
|
Repository repository = new Repository();
|
|
QuestService service = new QuestService(repository);
|
|
UUID issuer = UUID.randomUUID();
|
|
Quest quest = quest(service, issuer);
|
|
Inventory inventory = new Inventory();
|
|
inventory.overflow = 2;
|
|
RecordingNotifier notifier = new RecordingNotifier();
|
|
QuestCompletionController controller = new QuestCompletionController(
|
|
service, inventory, notifier
|
|
);
|
|
Player player = mock(Player.class);
|
|
|
|
controller.complete(player, quest.id().toString(), Instant.EPOCH.plusSeconds(1));
|
|
|
|
assertEquals("STONE", inventory.material);
|
|
assertEquals(3, inventory.amount);
|
|
assertTrue(inventory.granted);
|
|
assertFalse(inventory.rolledBack);
|
|
assertEquals(issuer, notifier.issuer);
|
|
assertEquals(
|
|
List.of(new EscrowItem("STONE", 3, null)),
|
|
service.state().claims().get(issuer).getFirst().items()
|
|
);
|
|
verify(player).sendMessage(contains("exact escrowed reward"));
|
|
verify(player).sendMessage(contains("dropped safely at your feet"));
|
|
}
|
|
|
|
@Test
|
|
void inventoryValidationFailureConsumesAndReleasesNothing() throws Exception {
|
|
Repository repository = new Repository();
|
|
QuestService service = new QuestService(repository);
|
|
Quest quest = quest(service, UUID.randomUUID());
|
|
Inventory inventory = new Inventory();
|
|
inventory.insufficient = true;
|
|
Player player = mock(Player.class);
|
|
|
|
assertThrows(IllegalArgumentException.class, () -> new QuestCompletionController(
|
|
service, inventory, ignored -> { }
|
|
).complete(player, quest.id().toString(), Instant.EPOCH.plusSeconds(1)));
|
|
|
|
assertFalse(inventory.granted);
|
|
assertEquals(QuestStatus.ACTIVE, service.state().quests().get(quest.id()).status());
|
|
assertTrue(service.state().claims().isEmpty());
|
|
verify(player, never()).sendMessage(contains("completed"));
|
|
}
|
|
|
|
@Test
|
|
void persistenceFailureRollsBackDeliveryAndDoesNotGrantReward() throws Exception {
|
|
Repository repository = new Repository();
|
|
QuestService service = new QuestService(repository);
|
|
Quest quest = quest(service, UUID.randomUUID());
|
|
Inventory inventory = new Inventory();
|
|
repository.fail = true;
|
|
|
|
assertThrows(IOException.class, () -> new QuestCompletionController(
|
|
service, inventory, ignored -> { }
|
|
).complete(mock(Player.class), quest.id().toString(), Instant.EPOCH.plusSeconds(1)));
|
|
|
|
assertTrue(inventory.rolledBack);
|
|
assertFalse(inventory.granted);
|
|
assertEquals(QuestStatus.ACTIVE, service.state().quests().get(quest.id()).status());
|
|
}
|
|
|
|
private static Quest quest(QuestService service, UUID issuer) throws IOException {
|
|
return service.create(
|
|
issuer, "Issuer", "STONE", 3,
|
|
List.of(new EscrowItem("DIAMOND", 2, null)), Instant.EPOCH
|
|
);
|
|
}
|
|
|
|
private static final class Inventory implements QuestCompletionInventory {
|
|
private String material;
|
|
private int amount;
|
|
private boolean insufficient;
|
|
private boolean rolledBack;
|
|
private boolean granted;
|
|
private int overflow;
|
|
|
|
@Override
|
|
public RemovedDelivery remove(Player player, String requestedMaterial, int requestedAmount) {
|
|
material = requestedMaterial;
|
|
amount = requestedAmount;
|
|
if (insufficient) {
|
|
throw new IllegalArgumentException("not enough blocks");
|
|
}
|
|
return new RemovedDelivery() {
|
|
@Override
|
|
public List<EscrowItem> items() {
|
|
return List.of(new EscrowItem(requestedMaterial, requestedAmount, null));
|
|
}
|
|
|
|
@Override public void rollback() { rolledBack = true; }
|
|
};
|
|
}
|
|
|
|
@Override
|
|
public PreparedReward prepare(List<EscrowItem> reward) {
|
|
return player -> {
|
|
granted = true;
|
|
return overflow;
|
|
};
|
|
}
|
|
}
|
|
|
|
private static final class RecordingNotifier implements IssuerNotifier {
|
|
private UUID issuer;
|
|
@Override public void notifyIfOnline(UUID issuerId) { issuer = issuerId; }
|
|
}
|
|
|
|
private static final class Repository implements QuestRepository {
|
|
private QuestState state = QuestState.empty();
|
|
private boolean fail;
|
|
@Override public QuestState load() { return state; }
|
|
@Override public void save(QuestState candidate) throws IOException {
|
|
if (fail) {
|
|
throw new IOException("disk full");
|
|
}
|
|
state = candidate;
|
|
}
|
|
}
|
|
}
|