Add support for join, leave, and info signs.

The ability to execute commands by hitting signs is already implemented by other plugins, but by creating built-in support for such signs, it's possible to leverage information about the plugin and its current state. This implementation allows for displaying live information about player counts, waves, etc. on the signs in addition to tying actions to them.

Customizable templates defined in the new signs.yml config-file can be bound to signs during the in-game sign creation, and users can define state-specific templates that change based on whether an arena is completely idle, has players in the lobby, or is running and in full swing.

Sign data is stored in data/signs.data as a YAML-formatted file that shouldn't be modified directly, effectively separating configuration (templates in signs.yml) and data (coordinates and parameters in signs.data).

Closes #385
This commit is contained in:
Andreas Troelsen
2018-06-14 00:29:11 +02:00
parent 42416cab2f
commit 84249640d1
32 changed files with 2102 additions and 0 deletions
@@ -0,0 +1,57 @@
package com.garbagemule.MobArena.signs;
import static org.hamcrest.MatcherAssert.*;
import static org.hamcrest.Matchers.*;
import static org.mockito.Mockito.*;
import org.bukkit.Location;
import org.bukkit.World;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.junit.MockitoJUnitRunner;
import java.util.HashMap;
import java.util.Map;
@RunWith(MockitoJUnitRunner.StrictStubs.class)
public class ArenaSignTest {
@Test
public void serialize() {
World world = mock(World.class);
Location location = new Location(world, 1, 2, 3);
String templateId = "a good template";
String arenaId = "cool arena";
String type = "join";
ArenaSign sign = new ArenaSign(location, templateId, arenaId, type);
Map<String, Object> result = sign.serialize();
assertThat(result.get("location"), equalTo(location));
assertThat(result.get("templateId"), equalTo(templateId));
assertThat(result.get("arenaId"), equalTo(arenaId));
assertThat(result.get("type"), equalTo(type));
}
@Test
public void deserialize() {
World world = mock(World.class);
Location location = new Location(world, 1, 2, 3);
String templateId = "a good template";
String arenaId = "cool arena";
String type = "join";
Map<String, Object> map = new HashMap<>();
map.put("location", location);
map.put("templateId", templateId);
map.put("arenaId", arenaId);
map.put("type", type);
ArenaSign result = ArenaSign.deserialize(map);
assertThat(result.location, is(equalTo(location)));
assertThat(result.templateId, is(equalTo(templateId)));
assertThat(result.arenaId, is(equalTo(arenaId)));
assertThat(result.type, is(equalTo(type)));
}
}
@@ -0,0 +1,89 @@
package com.garbagemule.MobArena.signs;
import static org.mockito.Mockito.*;
import org.bukkit.Location;
import org.bukkit.block.Block;
import org.bukkit.block.Chest;
import org.bukkit.block.Sign;
import org.bukkit.entity.Player;
import org.bukkit.event.player.PlayerInteractEvent;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.junit.MockitoJUnitRunner;
import java.util.Optional;
@SuppressWarnings("WeakerAccess")
@RunWith(MockitoJUnitRunner.StrictStubs.class)
public class HandlesSignClicksTest {
SignStore signStore;
InvokesSignAction invokesSignAction;
HandlesSignClicks subject;
@Before
public void setup() {
signStore = mock(SignStore.class);
when(signStore.findByLocation(any()))
.thenReturn(Optional.empty());
invokesSignAction = mock(InvokesSignAction.class);
subject = new HandlesSignClicks(signStore, invokesSignAction);
}
@Test
public void noBlockNoFun() {
PlayerInteractEvent event = event(null, null);
subject.on(event);
verifyZeroInteractions(signStore);
}
@Test
public void noSignBlockNoFun() {
Block block = mock(Block.class);
when(block.getState()).thenReturn(mock(Chest.class));
PlayerInteractEvent event = event(null, block);
subject.on(event);
verifyZeroInteractions(signStore);
}
@Test
public void nonArenaSignNoFun() {
Block block = mock(Block.class);
when(block.getState()).thenReturn(mock(Sign.class));
PlayerInteractEvent event = event(null, block);
subject.on(event);
verifyZeroInteractions(signStore);
}
@Test
public void arenaSignInvokesAction() {
Location location = mock(Location.class);
Block block = mock(Block.class);
when(block.getLocation()).thenReturn(location);
when(block.getState()).thenReturn(mock(Sign.class));
ArenaSign sign = new ArenaSign(location, "", "", "");
when(signStore.findByLocation(location))
.thenReturn(Optional.of(sign));
Player player = mock(Player.class);
PlayerInteractEvent event = event(player, block);
subject.on(event);
verify(invokesSignAction).invoke(sign, player);
}
private PlayerInteractEvent event(Player player, Block block) {
return new PlayerInteractEvent(player, null, null, block, null);
}
}
@@ -0,0 +1,146 @@
package com.garbagemule.MobArena.signs;
import static org.mockito.Mockito.*;
import com.garbagemule.MobArena.Messenger;
import org.bukkit.Location;
import org.bukkit.block.Block;
import org.bukkit.entity.Player;
import org.bukkit.event.block.SignChangeEvent;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.junit.MockitoJUnitRunner;
@SuppressWarnings("WeakerAccess")
@RunWith(MockitoJUnitRunner.StrictStubs.class)
public class HandlesSignCreationTest {
StoresNewSign storesNewSign;
RendersTemplateById rendersTemplate;
Messenger messenger;
HandlesSignCreation subject;
@Before
public void setup() {
storesNewSign = mock(StoresNewSign.class);
rendersTemplate = mock(RendersTemplateById.class);
when(rendersTemplate.render(any(), any()))
.thenReturn(new String[]{"", "", "", ""});
messenger = mock(Messenger.class);
subject = new HandlesSignCreation(
storesNewSign,
rendersTemplate,
messenger
);
}
@Test
public void noHeaderNoAction() {
String[] lines = {"why", "so", "serious", "?"};
SignChangeEvent event = event(lines, null);
subject.on(event);
verifyZeroInteractions(storesNewSign, rendersTemplate, messenger);
}
@Test
public void nullLinesHandledGracefully() {
String[] lines = {"[MA]", null, null, null};
SignChangeEvent event = event(lines, null);
subject.on(event);
}
@Test
public void useSignTypeIfTemplateNotAvailable() {
String arenaId = "castle";
String type = "join";
String[] lines = {"[MA]", arenaId, type, null};
Location location = mock(Location.class);
SignChangeEvent event = event(lines, location);
subject.on(event);
verify(storesNewSign).store(location, arenaId, type, type);
}
@Test
public void useTemplateIfAvailable() {
String arenaId = "castle";
String type = "join";
String templateId = "potato";
String[] lines = {"[MA]", arenaId, type, templateId};
Location location = mock(Location.class);
SignChangeEvent event = event(lines, location);
subject.on(event);
verify(storesNewSign).store(location, arenaId, templateId, type);
}
@Test
public void typeIsLowercased() {
String type = "JOIN";
String[] lines = {"[MA]", "", type, ""};
SignChangeEvent event = event(lines, null);
subject.on(event);
String lower = type.toLowerCase();
verify(storesNewSign).store(any(), any(), any(), eq(lower));
}
@Test
public void templateIdIsLowercased() {
String templateId = "BEST-TEMPLATE";
String[] lines = {"[MA]", "", "", templateId};
SignChangeEvent event = event(lines, null);
subject.on(event);
String lower = templateId.toLowerCase();
verify(storesNewSign).store(any(), any(), eq(lower), any());
}
@Test
public void rendersTemplateAfterStoring() {
String arenaId = "castle";
String type = "join";
String templateId = "potato";
String[] lines = {"[MA]", arenaId, type, templateId};
Location location = mock(Location.class);
SignChangeEvent event = event(lines, location);
subject.on(event);
verify(rendersTemplate).render(templateId, arenaId);
}
@Test
public void errorPassedToMessenger() {
String msg = "you messed up";
doThrow(new IllegalArgumentException(msg))
.when(storesNewSign).store(any(), any(), any(), any());
String[] lines = {"[MA]", "", "", ""};
SignChangeEvent event = event(lines, null);
subject.on(event);
verifyZeroInteractions(rendersTemplate);
verify(messenger).tell(event.getPlayer(), msg);
}
private SignChangeEvent event(String[] lines, Location location) {
Block block = mock(Block.class);
when(block.getLocation()).thenReturn(location);
Player player = mock(Player.class);
return new SignChangeEvent(block, player, lines);
}
}
@@ -0,0 +1,63 @@
package com.garbagemule.MobArena.signs;
import static org.mockito.Mockito.*;
import com.garbagemule.MobArena.Messenger;
import org.bukkit.block.Block;
import org.bukkit.entity.Player;
import org.bukkit.event.block.BlockBreakEvent;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.junit.MockitoJUnitRunner;
import java.util.Optional;
@SuppressWarnings("WeakerAccess")
@RunWith(MockitoJUnitRunner.StrictStubs.class)
public class HandlesSignDestructionTest {
RemovesSignAtLocation removesSignAtLocation;
Messenger messenger;
HandlesSignDestruction subject;
@Before
public void setup() {
removesSignAtLocation = mock(RemovesSignAtLocation.class);
messenger = mock(Messenger.class);
subject = new HandlesSignDestruction(
removesSignAtLocation,
messenger
);
}
@Test
public void doesNothingWithNonArenaSign() {
Block block = mock(Block.class);
Player player = mock(Player.class);
when(removesSignAtLocation.remove(any()))
.thenReturn(Optional.empty());
BlockBreakEvent event = new BlockBreakEvent(block, player);
subject.on(event);
verifyZeroInteractions(messenger);
}
@Test
public void reportsBreakageWithArenaSign() {
Block block = mock(Block.class);
Player player = mock(Player.class);
ArenaSign sign = new ArenaSign(null, "", "", "");
when(removesSignAtLocation.remove(any()))
.thenReturn(Optional.of(sign));
BlockBreakEvent event = new BlockBreakEvent(block, player);
subject.on(event);
verify(messenger).tell(eq(player), anyString());
}
}
@@ -0,0 +1,115 @@
package com.garbagemule.MobArena.signs;
import static org.mockito.Mockito.*;
import com.garbagemule.MobArena.Messenger;
import com.garbagemule.MobArena.framework.Arena;
import com.garbagemule.MobArena.framework.ArenaMaster;
import org.bukkit.entity.Player;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.junit.MockitoJUnitRunner;
@SuppressWarnings("WeakerAccess")
@RunWith(MockitoJUnitRunner.StrictStubs.class)
public class InvokesSignActionTest {
ArenaMaster arenaMaster;
Messenger messenger;
InvokesSignAction subject;
@Before
public void setup() {
arenaMaster = mock(ArenaMaster.class);
messenger = mock(Messenger.class);
subject = new InvokesSignAction(arenaMaster, messenger);
}
@Test
public void infoSignDoesNothing() {
String arenaId = "castle";
ArenaSign sign = new ArenaSign(null, "", arenaId, "info");
Player player = mock(Player.class);
subject.invoke(sign, player);
verifyZeroInteractions(arenaMaster);
}
@Test
public void joinSignCallsCanJoin() {
String arenaId = "castle";
ArenaSign sign = new ArenaSign(null, "", arenaId, "join");
Player player = mock(Player.class);
Arena arena = mock(Arena.class);
when(arenaMaster.getArenaWithName(arenaId))
.thenReturn(arena);
subject.invoke(sign, player);
verify(arena).canJoin(player);
}
@Test
public void joinSignCallsPlayerJoin() {
String arenaId = "castle";
ArenaSign sign = new ArenaSign(null, "", arenaId, "join");
Player player = mock(Player.class);
Arena arena = mock(Arena.class);
when(arena.canJoin(player)).thenReturn(true);
when(arenaMaster.getArenaWithName(arenaId))
.thenReturn(arena);
subject.invoke(sign, player);
verify(arena).playerJoin(eq(player), any());
}
@Test
public void leaveSignCallsInChecks() {
String arenaId = "castle";
ArenaSign sign = new ArenaSign(null, "", arenaId, "leave");
Player player = mock(Player.class);
Arena arena = mock(Arena.class);
when(arenaMaster.getArenaWithName(arenaId))
.thenReturn(arena);
subject.invoke(sign, player);
verify(arena).inArena(player);
verify(arena).inLobby(player);
verify(arena).inSpec(player);
}
@Test
public void leaveSignCallsPlayerLeave() {
String arenaId = "castle";
ArenaSign sign = new ArenaSign(null, "", arenaId, "leave");
Player player = mock(Player.class);
Arena arena = mock(Arena.class);
when(arena.inArena(player)).thenReturn(true);
when(arenaMaster.getArenaWithName(arenaId))
.thenReturn(arena);
subject.invoke(sign, player);
verify(arena).playerLeave(player);
}
@Test
public void nonExistentArenaReportsToPlayer() {
String arenaId = "castle";
ArenaSign sign = new ArenaSign(null, "", arenaId, "join");
Player player = mock(Player.class);
when(arenaMaster.getArenaWithName(arenaId))
.thenReturn(null);
subject.invoke(sign, player);
verify(messenger).tell(eq(player), anyString());
}
}
@@ -0,0 +1,141 @@
package com.garbagemule.MobArena.signs;
import static org.mockito.Mockito.*;
import com.garbagemule.MobArena.framework.Arena;
import org.bukkit.Location;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.junit.MockitoJUnitRunner;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
@SuppressWarnings("WeakerAccess")
@RunWith(MockitoJUnitRunner.StrictStubs.class)
public class RedrawsArenaSignsTest {
SignStore signStore;
TemplateStore templateStore;
RendersTemplate rendersTemplate;
SetsLines setsSignLines;
RedrawsArenaSigns subject;
@Before
public void setup() {
signStore = mock(SignStore.class);
when(signStore.findByArenaId(any()))
.thenReturn(Collections.emptyList());
templateStore = mock(TemplateStore.class);
when(templateStore.findById(any()))
.thenReturn(Optional.empty());
rendersTemplate = mock(RendersTemplate.class);
when(rendersTemplate.render(any(), any()))
.thenReturn(new String[]{"a", "b", "c", "d"});
setsSignLines = mock(SetsLines.class);
subject = new RedrawsArenaSigns(
signStore,
templateStore,
rendersTemplate,
setsSignLines
);
}
@Test
public void noSignsMeansNoRenderingOrLineSetting() {
Arena arena = arena("castle");
subject.redraw(arena);
verifyZeroInteractions(rendersTemplate);
verifyZeroInteractions(setsSignLines);
}
@Test
public void renderFoundTemplate() {
String arenaId = "castle";
Arena arena = arena(arenaId);
ArenaSign sign = sign("join", arenaId);
when(signStore.findByArenaId(arenaId))
.thenReturn(Collections.singletonList(sign));
Template template = template("template", "some", "info", "about", "arena");
when(templateStore.findById(sign.templateId))
.thenReturn(Optional.of(template));
subject.redraw(arena);
verify(rendersTemplate).render(template, arena);
}
@Test
public void setRenderedTemplateOnSign() {
String arenaId = "castle";
Arena arena = arena(arenaId);
ArenaSign sign = sign("join", arenaId);
when(signStore.findByArenaId(sign.arenaId))
.thenReturn(Collections.singletonList(sign));
Template template = template("template", "try", "with", "more", "fireballs");
when(templateStore.findById(sign.templateId))
.thenReturn(Optional.of(template));
String[] lines = new String[]{"this", "is", "a", "sign"};
when(rendersTemplate.render(template, arena))
.thenReturn(lines);
subject.redraw(arena);
verify(setsSignLines).set(sign.location, lines);
}
@Test
public void renderEachTemplateOnlyOnce() {
String arenaId = "castle";
Arena arena = arena(arenaId);
String templateId1 = "join";
String templateId2 = "info";
List<ArenaSign> signs = new ArrayList<>();
signs.add(sign(templateId1, arenaId));
signs.add(sign(templateId1, arenaId));
signs.add(sign(templateId1, arenaId));
signs.add(sign(templateId2, arenaId));
when(signStore.findByArenaId(arenaId))
.thenReturn(signs);
Template template1 = template(templateId1, "join", "a", "MobArena", "today!");
Template template2 = template(templateId2, "join", "another", "MobArena", "tomorrow!");
when(templateStore.findById(templateId1))
.thenReturn(Optional.of(template1));
when(templateStore.findById(templateId2))
.thenReturn(Optional.of(template2));
subject.redraw(arena);
verify(rendersTemplate, times(1)).render(template1, arena);
verify(rendersTemplate, times(1)).render(template2, arena);
verify(setsSignLines, times(signs.size())).set(any(), any());
}
private Arena arena(String arenaId) {
Arena arena = mock(Arena.class);
when(arena.configName()).thenReturn(arenaId);
return arena;
}
private ArenaSign sign(String templateId, String arenaId) {
Location location = mock(Location.class);
return new ArenaSign(location, templateId, arenaId, "join");
}
private Template template(String id, String l1, String l2, String l3, String l4) {
return new Template.Builder(id)
.withBase(new String[]{l1, l2, l3, l4})
.build();
}
}
@@ -0,0 +1,56 @@
package com.garbagemule.MobArena.signs;
import static org.mockito.Mockito.*;
import org.bukkit.Location;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.junit.MockitoJUnitRunner;
import java.util.Optional;
@SuppressWarnings("WeakerAccess")
@RunWith(MockitoJUnitRunner.StrictStubs.class)
public class RemovesSignAtLocationTest {
SignStore signStore;
SavesSignStore savesSignStore;
RemovesSignAtLocation subject;
@Before
public void setup() {
signStore = mock(SignStore.class);
savesSignStore = mock(SavesSignStore.class);
subject = new RemovesSignAtLocation(
signStore,
savesSignStore
);
}
@Test
public void noSignMeansNoWrite() {
Location location = mock(Location.class);
when(signStore.remove(location))
.thenReturn(Optional.empty());
subject.remove(location);
verifyZeroInteractions(savesSignStore);
}
@Test
public void signRemovedWritesStore() {
Location location = mock(Location.class);
ArenaSign sign = new ArenaSign(location, "", "", "");
when(signStore.remove(location))
.thenReturn(Optional.of(sign));
subject.remove(location);
verify(savesSignStore).save(signStore);
}
}
@@ -0,0 +1,106 @@
package com.garbagemule.MobArena.signs;
import static org.hamcrest.MatcherAssert.*;
import static org.hamcrest.Matchers.*;
import static org.mockito.Mockito.*;
import com.garbagemule.MobArena.framework.Arena;
import com.garbagemule.MobArena.waves.WaveManager;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.junit.MockitoJUnitRunner;
import java.util.Collections;
@SuppressWarnings("WeakerAccess")
@RunWith(MockitoJUnitRunner.StrictStubs.class)
public class RendersTemplateTest {
RendersTemplate subject;
@Before
public void setup() {
subject = new RendersTemplate();
}
@Test
public void rendersArenaName() {
String name = "castle";
Arena arena = arena(name, false, false);
Template template = new Template.Builder("template")
.withBase(new String[]{"<arena-name>", "", "", ""})
.build();
String[] result = subject.render(template, arena);
String[] expected = new String[]{name, "", "", ""};
assertThat(result, equalTo(expected));
}
@Test
public void defaultsToBaseIfArenaIsNotRunning() {
Arena arena = arena("castle", false, false);
String[] base = {"this", "is", "the", "base"};
Template template = new Template.Builder("template")
.withBase(base)
.withRunning(new String[]{"here", "is", "running", "yo"})
.build();
String[] result = subject.render(template, arena);
assertThat(result, equalTo(base));
}
@Test
public void idleOverridesBaseIfNotRunning() {
Arena arena = arena("castle", false, false);
String[] idle = {"relax", "don't", "do", "it"};
Template template = new Template.Builder("template")
.withBase(new String[]{"this", "is", "the", "base"})
.withIdle(idle)
.build();
String[] result = subject.render(template, arena);
assertThat(result, equalTo(idle));
}
@Test
public void runningOverridesBaseIfArenaIsRunning() {
Arena arena = arena("castle", true, false);
String[] running = {"here", "is", "running", "yo"};
Template template = new Template.Builder("template")
.withBase(new String[]{"this", "is", "the", "base"})
.withRunning(running)
.build();
String[] result = subject.render(template, arena);
assertThat(result, equalTo(running));
}
@Test
public void lobbyOverridesBaseIfPlayersInLobby() {
Arena arena = arena("castle", false, true);
String[] joining = {"we", "in", "da", "lobby"};
Template template = new Template.Builder("template")
.withBase(new String[]{"this", "is", "the", "base"})
.withJoining(joining)
.build();
String[] result = subject.render(template, arena);
assertThat(result, equalTo(joining));
}
private Arena arena(String name, boolean running, boolean lobby) {
Arena arena = mock(Arena.class);
when(arena.configName()).thenReturn(name);
when(arena.isRunning()).thenReturn(running);
when(arena.getPlayersInLobby()).thenReturn(lobby ? Collections.singleton(null) : Collections.emptySet());
when(arena.getWaveManager()).thenReturn(mock(WaveManager.class));
return arena;
}
}
@@ -0,0 +1,126 @@
package com.garbagemule.MobArena.signs;
import static org.hamcrest.MatcherAssert.*;
import static org.hamcrest.Matchers.*;
import static org.mockito.Mockito.*;
import com.garbagemule.MobArena.framework.Arena;
import com.garbagemule.MobArena.framework.ArenaMaster;
import org.bukkit.Location;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.junit.MockitoJUnitRunner;
import java.util.Optional;
@SuppressWarnings("WeakerAccess")
@RunWith(MockitoJUnitRunner.StrictStubs.class)
public class StoresNewSignTest {
ArenaMaster arenaMaster;
TemplateStore templateStore;
SignStore signStore;
SavesSignStore savesSignStore;
StoresNewSign subject;
@Rule
public ExpectedException exception = ExpectedException.none();
@Before
public void setup() {
arenaMaster = mock(ArenaMaster.class);
when(arenaMaster.getArenaWithName(any()))
.thenReturn(null);
templateStore = mock(TemplateStore.class);
when(templateStore.findById(any()))
.thenReturn(Optional.empty());
signStore = mock(SignStore.class);
savesSignStore = mock(SavesSignStore.class);
subject = new StoresNewSign(
arenaMaster,
templateStore,
signStore,
savesSignStore
);
}
@Test
public void throwOnNonExistentArena() {
Location location = mock(Location.class);
String arenaId = "castle";
exception.expect(IllegalArgumentException.class);
subject.store(location, arenaId, "", "");
}
@Test
public void throwOnNonExistentTemplate() {
Location location = mock(Location.class);
String arenaId = "castle";
Arena arena = mock(Arena.class);
when(arenaMaster.getArenaWithName(arenaId))
.thenReturn(arena);
String templateId = "template";
exception.expect(IllegalArgumentException.class);
subject.store(location, arenaId, templateId, "");
}
@Test
public void throwOnNonInvalidSignType() {
Location location = mock(Location.class);
String arenaId = "castle";
Arena arena = mock(Arena.class);
when(arenaMaster.getArenaWithName(arenaId))
.thenReturn(arena);
String templateId = "a very nice template";
Template template = template(templateId);
when(templateStore.findById(templateId))
.thenReturn(Optional.of(template));
String signType = "not a real sign type";
exception.expect(IllegalArgumentException.class);
subject.store(location, arenaId, templateId, signType);
}
@Test
public void storesSignAndWritesToDisk() {
Location location = mock(Location.class);
String arenaId = "castle";
Arena arena = mock(Arena.class);
when(arenaMaster.getArenaWithName(arenaId))
.thenReturn(arena);
String templateId = "a very nice template";
Template template = template(templateId);
when(templateStore.findById(templateId))
.thenReturn(Optional.of(template));
String signType = "join";
subject.store(location, arenaId, templateId, signType);
ArgumentCaptor<ArenaSign> captor = ArgumentCaptor.forClass(ArenaSign.class);
verify(signStore).store(captor.capture());
verify(savesSignStore).save(signStore);
ArenaSign sign = captor.getValue();
assertThat(sign.location, equalTo(location));
assertThat(sign.arenaId, equalTo(arenaId));
assertThat(sign.templateId, equalTo(templateId));
assertThat(sign.type, equalTo(signType));
}
private Template template(String id) {
return new Template.Builder(id)
.withBase(new String[]{"", "", "", ""})
.build();
}
}