Skip to content

Commit

Permalink
Add method to get back a builder from a DraftPunishment
Browse files Browse the repository at this point in the history
* Helps with #130
* Add Test
* Also add similar method for CalculablePunishment (added since
  original PR).

Co-authored-by: MCMDEV <[email protected]>
Co-authored-by: KoxSosen <[email protected]>
  • Loading branch information
2 people authored and A248 committed Sep 12, 2023
1 parent fdf46d9 commit eeda754
Show file tree
Hide file tree
Showing 7 changed files with 190 additions and 43 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -39,4 +39,11 @@ public interface CalculablePunishment extends DraftSanction {
*/
EscalationTrack getEscalationTrack();

/**
* Creates a new {@link CalculablePunishmentBuilder}, copying all properties of this calculable.
*
* @return A new builder
*/
CalculablePunishmentBuilder toBuilder();

}
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,13 @@ default ReactionStage<Optional<Punishment>> enactPunishment() {
@Override
ReactionStage<Optional<Punishment>> enactPunishment(EnforcementOptions enforcementOptions);

/**
* Creates a new {@link DraftPunishmentBuilder}, copying all properties of this draft.
*
* @return A new builder
*/
DraftPunishmentBuilder toBuilder();

@Override
boolean equals(Object object);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,26 +23,23 @@
import jakarta.inject.Singleton;
import space.arim.libertybans.api.event.PunishEvent;
import space.arim.libertybans.api.punish.DraftPunishment;
import space.arim.libertybans.api.punish.PunishmentDrafter;
import space.arim.libertybans.core.event.PunishEventImpl;
import space.arim.omnibus.events.ListeningMethod;

@Singleton
public final class ShortcutReasonsListener {

private final ShortcutReasonsAddon addon;
private final PunishmentDrafter drafter;

@Inject
public ShortcutReasonsListener(ShortcutReasonsAddon addon, PunishmentDrafter drafter) {
public ShortcutReasonsListener(ShortcutReasonsAddon addon) {
this.addon = addon;
this.drafter = drafter;
}

@ListeningMethod
public void onPunish(PunishEvent event) {
ShortcutReasonsConfig config = addon.config();
DraftPunishment originalPunishment = event.getDraftPunishment();
DraftPunishment originalPunishment = event.getDraftSanction();
String originalReason = originalPunishment.getReason();
String shortcutIdentifier = config.shortcutIdentifier();
if (!originalReason.startsWith(shortcutIdentifier)) {
Expand All @@ -56,17 +53,8 @@ public void onPunish(PunishEvent event) {
event.cancel();
return;
}
// TODO Cleanup by using originalPunishment.toBuilder()
event.setDraftPunishment(drafter
.draftBuilder()
.type(originalPunishment.getType())
.victim(originalPunishment.getVictim())
.operator(originalPunishment.getOperator())
.reason(newReason)
.duration(originalPunishment.getDuration())
.scope(originalPunishment.getScope())
.build()
);
DraftPunishment newPunishment = originalPunishment.toBuilder().reason(newReason).build();
event.setDraftSanction(newPunishment);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -27,27 +27,21 @@
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import space.arim.api.jsonchat.adventure.util.ComponentText;
import space.arim.libertybans.api.AddressVictim;
import space.arim.libertybans.api.ConsoleOperator;
import space.arim.libertybans.api.PunishmentType;
import space.arim.libertybans.api.punish.DraftPunishment;
import space.arim.libertybans.api.punish.DraftPunishmentBuilder;
import space.arim.libertybans.api.punish.PunishmentDrafter;
import space.arim.libertybans.core.addon.AddonCenter;
import space.arim.libertybans.core.addon.shortcutreasons.ShortcutReasonsAddon;
import space.arim.libertybans.core.addon.shortcutreasons.ShortcutReasonsConfig;
import space.arim.libertybans.core.addon.shortcutreasons.ShortcutReasonsListener;
import space.arim.libertybans.core.env.CmdSender;
import space.arim.libertybans.core.event.PunishEventImpl;
import space.arim.libertybans.core.scope.ScopeImpl;
import space.arim.omnibus.DefaultOmnibus;
import space.arim.omnibus.Omnibus;

import java.util.Map;

import static org.junit.jupiter.api.Assertions.assertSame;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
Expand All @@ -57,21 +51,19 @@
public class ShortcutReasonsListenerTest {

private final Omnibus omnibus = new DefaultOmnibus();
private final PunishmentDrafter drafter;
private final ShortcutReasonsConfig config;

private ShortcutReasonsAddon addon;
private ShortcutReasonsListener listener;

public ShortcutReasonsListenerTest(@Mock PunishmentDrafter drafter, @Mock ShortcutReasonsConfig config) {
public ShortcutReasonsListenerTest(@Mock ShortcutReasonsConfig config) {
this.config = config;
this.drafter = drafter;
}

@BeforeEach
public void setupListener(@Mock AddonCenter addonCenter) {
addon = new ShortcutReasonsAddon(addonCenter, omnibus, () -> listener);
listener = new ShortcutReasonsListener(addon, drafter);
listener = new ShortcutReasonsListener(addon);
when(addonCenter.configurationFor(addon)).thenReturn(config);

addon.startup();
Expand All @@ -87,7 +79,7 @@ public void noMatch(@Mock DraftPunishment draftPunishment) {
when(config.shortcutIdentifier()).thenReturn("#");
when(draftPunishment.getReason()).thenReturn("no match");
var event = fireEvent(draftPunishment);
assertSame(draftPunishment, event.getDraftPunishment());
assertSame(draftPunishment, event.getDraftSanction());
verifyNoMoreInteractions(event.getSender());
}

Expand All @@ -100,23 +92,13 @@ public void simpleSubstitute(@Mock DraftPunishment draftPunishment,
"spamming", "don't be a spammer, thank you"
));

when(draftPunishment.getType()).thenReturn(PunishmentType.KICK);
when(draftPunishment.getVictim()).thenReturn(AddressVictim.of(new byte[4]));
when(draftPunishment.getOperator()).thenReturn(ConsoleOperator.INSTANCE);
when(draftPunishment.getReason()).thenReturn("#hacking");
when(draftPunishment.getScope()).thenReturn(ScopeImpl.GLOBAL);

when(drafter.draftBuilder()).thenReturn(newBuilder);
when(newBuilder.type(PunishmentType.KICK)).thenReturn(newBuilder);
when(newBuilder.victim(AddressVictim.of(new byte[4]))).thenReturn(newBuilder);
when(newBuilder.operator(ConsoleOperator.INSTANCE)).thenReturn(newBuilder);
when(draftPunishment.toBuilder()).thenReturn(newBuilder);
when(newBuilder.reason("hello hackers")).thenReturn(newBuilder);
when(newBuilder.duration(any())).thenReturn(newBuilder);
when(newBuilder.scope(ScopeImpl.GLOBAL)).thenReturn(newBuilder);
when(newBuilder.build()).thenReturn(newPunishment);

var event = fireEvent(draftPunishment);
assertSame(newPunishment, event.getDraftPunishment());
assertSame(newPunishment, event.getDraftSanction());
verifyNoMoreInteractions(event.getSender());
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,8 @@

package space.arim.libertybans.core.punish;

import space.arim.libertybans.api.Operator;
import space.arim.libertybans.api.Victim;
import space.arim.libertybans.api.punish.CalculablePunishment;
import space.arim.libertybans.api.punish.CalculablePunishmentBuilder;
import space.arim.libertybans.api.punish.EnforcementOptions;
import space.arim.libertybans.api.punish.EscalationTrack;
import space.arim.libertybans.api.punish.Punishment;
Expand Down Expand Up @@ -55,6 +54,15 @@ public EscalationTrack getEscalationTrack() {
return escalationTrack;
}

@Override
public CalculablePunishmentBuilder toBuilder() {
return enactor.calculablePunishmentBuilder()
.victim(getVictim())
.operator(getOperator())
.calculator(getCalculator())
.escalationTrack(getEscalationTrack());
}

@Override
public ReactionStage<Optional<Punishment>> enactPunishment(EnforcementOptions enforcementOptions) {
return enactor.calculatePunishment(this).thenCompose((punishment) -> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import java.util.Optional;
import java.util.concurrent.CompletableFuture;

import space.arim.libertybans.api.punish.DraftPunishmentBuilder;
import space.arim.libertybans.api.punish.EnforcementOptions;
import space.arim.omnibus.util.concurrent.ReactionStage;

Expand Down Expand Up @@ -55,6 +56,18 @@ public ReactionStage<Optional<Punishment>> enactPunishment(EnforcementOptions en
});
}

@Override
public DraftPunishmentBuilder toBuilder() {
return enactor.draftBuilder()
.type(getType())
.victim(getVictim())
.operator(getOperator())
.reason(getReason())
.duration(getDuration())
.scope(getScope())
.escalationTrack(getEscalationTrack().orElse(null));
}

@Override
public int hashCode() {
final int prime = 31;
Expand All @@ -71,10 +84,9 @@ public boolean equals(Object object) {
if (!super.equals(object)) {
return false;
}
if (!(object instanceof DraftPunishmentImpl)) {
if (!(object instanceof DraftPunishmentImpl other)) {
return false;
}
DraftPunishmentImpl other = (DraftPunishmentImpl) object;
return duration.equals(other.duration);
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
/*
* LibertyBans
* Copyright © 2023 Anand Beh
*
* LibertyBans is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* LibertyBans is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with LibertyBans. If not, see <https://www.gnu.org/licenses/>
* and navigate to version 3 of the GNU Affero General Public License.
*/

package space.arim.libertybans.core.punish;

import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import space.arim.libertybans.api.Operator;
import space.arim.libertybans.api.PlayerOperator;
import space.arim.libertybans.api.PlayerVictim;
import space.arim.libertybans.api.PunishmentType;
import space.arim.libertybans.api.Victim;
import space.arim.libertybans.api.punish.CalculablePunishment;
import space.arim.libertybans.api.punish.CalculablePunishmentBuilder;
import space.arim.libertybans.api.punish.DraftPunishment;
import space.arim.libertybans.api.punish.DraftPunishmentBuilder;
import space.arim.libertybans.api.punish.DraftSanction;
import space.arim.libertybans.api.punish.DraftSanctionBuilder;
import space.arim.libertybans.api.punish.EscalationTrack;
import space.arim.libertybans.api.punish.PunishmentDetailsCalculator;
import space.arim.libertybans.api.scope.ServerScope;
import space.arim.libertybans.core.scope.InternalScopeManager;
import space.arim.libertybans.core.scope.ScopeImpl;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.time.Duration;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.Mockito.when;

@ExtendWith(MockitoExtension.class)
public class PunishmentBuilderTest {

private final Enactor enactor;
private final InternalScopeManager scopeManager;

private final Map<Class<?>, Object> builderParameters = new HashMap<>();

public PunishmentBuilderTest(@Mock Enactor enactor, @Mock InternalScopeManager scopeManager) {
this.enactor = enactor;
this.scopeManager = scopeManager;
}

private <T> void addBuilderParam(Class<T> clazz, T value) {
builderParameters.put(clazz, value);
}

@BeforeEach
public void setup() {
when(enactor.scopeManager()).thenReturn(scopeManager);
when(scopeManager.globalScope()).thenReturn(ScopeImpl.GLOBAL);

addBuilderParam(Victim.class, PlayerVictim.of(UUID.randomUUID()));
addBuilderParam(Operator.class, PlayerOperator.of(UUID.randomUUID()));
addBuilderParam(EscalationTrack.class, EscalationTrack.create("hi", "there"));
}

private <B extends DraftSanctionBuilder<B, D>, D extends DraftSanction> void testBuilder(
Class<B> builderClass, Class<D> sanctionClass, B builder) {
for (Method method : builderClass.getMethods()) {
if (method.getParameterCount() != 1) {
continue;
}
Class<?> returnType = method.getReturnType();
if (!DraftSanctionBuilder.class.isAssignableFrom(returnType)) {
continue;
}
Class<?> argType = method.getParameterTypes()[0];
Object argValue = builderParameters.get(argType);
if (argValue == null) {
// The test should thus fail
continue;
}
argType.cast(argValue);
try {
Object newBuilder = method.invoke(builder, argValue);
builder = builderClass.cast(newBuilder);
} catch (IllegalAccessException | InvocationTargetException ex) {
throw new RuntimeException(ex);
}
}
D built = builder.build();
Object backToBuilder;
try {
Method toBuilderMethod = sanctionClass.getMethod("toBuilder");
backToBuilder = toBuilderMethod.invoke(built);
} catch (NoSuchMethodException | InvocationTargetException | IllegalAccessException ex) {
throw new RuntimeException(ex);
}
D rebuilt = builderClass.cast(backToBuilder).build();
assertEquals(built, rebuilt);
}

@Test
public void draftPunishmentBuilderBuild() {
when(enactor.draftBuilder()).thenAnswer((i) -> new DraftPunishmentBuilderImpl(enactor));

addBuilderParam(PunishmentType.class, PunishmentType.BAN);
addBuilderParam(String.class, "Test");
addBuilderParam(ServerScope.class, ScopeImpl.specificServer("serveme!"));
addBuilderParam(Duration.class, Duration.ofHours(3L));

testBuilder(
DraftPunishmentBuilder.class, DraftPunishment.class, enactor.draftBuilder()
);
}

@Test
public void calculablePunishmentBuilderBuild() {
when(enactor.calculablePunishmentBuilder()).thenReturn(new CalculablePunishmentBuilderImpl(enactor));

PunishmentDetailsCalculator calculator = (track, victim, selectionOrderBuilder) -> null;
addBuilderParam(PunishmentDetailsCalculator.class, calculator);

testBuilder(
CalculablePunishmentBuilder.class, CalculablePunishment.class, enactor.calculablePunishmentBuilder()
);
}

}

0 comments on commit eeda754

Please sign in to comment.