diff --git a/Mage.Common/src/main/java/mage/utils/testers/AmountTestableResult.java b/Mage.Common/src/main/java/mage/utils/testers/AmountTestableResult.java new file mode 100644 index 00000000000..75ac2a31f0e --- /dev/null +++ b/Mage.Common/src/main/java/mage/utils/testers/AmountTestableResult.java @@ -0,0 +1,29 @@ +package mage.utils.testers; + +import java.util.List; + +/** + * Part of testable game dialogs + * + * @author JayDi85 + */ +public class AmountTestableResult extends BaseTestableResult { + + int amount = 0; + + public void save(boolean status, List info, int amount) { + this.save(status, info); + this.amount = amount; + } + + @Override + public boolean isOk() { + return true; + } + + @Override + public void clear() { + super.clear(); + this.amount = 0; + } +} diff --git a/Mage.Common/src/main/java/mage/utils/testers/AnnounceXTestableDialog.java b/Mage.Common/src/main/java/mage/utils/testers/AnnounceXTestableDialog.java index bd346448472..7aae7d68846 100644 --- a/Mage.Common/src/main/java/mage/utils/testers/AnnounceXTestableDialog.java +++ b/Mage.Common/src/main/java/mage/utils/testers/AnnounceXTestableDialog.java @@ -25,7 +25,8 @@ class AnnounceXTestableDialog extends BaseTestableDialog { public AnnounceXTestableDialog(boolean isYou, boolean isMana, int min, int max) { super(String.format("player.announceX(%s)", isYou ? "you" : "AI"), - String.format("%s from %d to %d", isMana ? "mana" : "cost", min, max), ""); + String.format("%s from %d to %d", isMana ? "mana" : "cost", min, max), "", + new AmountTestableResult()); this.isYou = isYou; this.isMana = isMana; this.min = min; @@ -33,14 +34,15 @@ class AnnounceXTestableDialog extends BaseTestableDialog { } @Override - public List showDialog(Player player, Ability source, Game game, Player opponent) { + public void showDialog(Player player, Ability source, Game game, Player opponent) { Player choosingPlayer = this.isYou ? player : opponent; String message = "message with html"; int chooseRes; chooseRes = choosingPlayer.announceX(this.min, this.max, message, game, source, this.isMana); - List result = new ArrayList<>(); - result.add(getGroup() + " - " + this.getName() + " selected " + chooseRes); - return result; + List res = new ArrayList<>(); + res.add(getGroup() + " - " + this.getName() + " selected " + chooseRes); + + ((AmountTestableResult) this.getResult()).save(true, res, chooseRes); } static public void register(TestableDialogsRunner runner) { diff --git a/Mage.Common/src/main/java/mage/utils/testers/BaseTestableDialog.java b/Mage.Common/src/main/java/mage/utils/testers/BaseTestableDialog.java index 0ee78b67e51..f86d46d9b82 100644 --- a/Mage.Common/src/main/java/mage/utils/testers/BaseTestableDialog.java +++ b/Mage.Common/src/main/java/mage/utils/testers/BaseTestableDialog.java @@ -18,11 +18,13 @@ abstract class BaseTestableDialog implements TestableDialog { private final String group; private final String name; private final String description; + private final TestableResult result; - public BaseTestableDialog(String group, String name, String description) { + public BaseTestableDialog(String group, String name, String description, TestableResult result) { this.group = group; this.name = name; this.description = description; + this.result = result; } @Override @@ -41,13 +43,23 @@ abstract class BaseTestableDialog implements TestableDialog { } @Override - final public void showResult(Player player, Game game, String result) { + public void prepare() { + this.result.clear(); + } + + @Override + final public void showResult(Player player, Game game) { // show message with result - game.informPlayer(player, result); + game.informPlayer(player, String.join("
", getResult().getInfo())); // reset game and gui (in most use cases it must return to player's priority) game.firePriorityEvent(player.getId()); } + @Override + public TestableResult getResult() { + return this.result; + } + static Target createAnyTarget(int min, int max) { return createAnyTarget(min, max, false); } @@ -56,14 +68,6 @@ abstract class BaseTestableDialog implements TestableDialog { return new TargetPermanentOrPlayer(min, max).withNotTarget(notTarget); } - static Target createCreatureTarget(int min, int max) { - return createCreatureTarget(min, max, false); - } - - private static Target createCreatureTarget(int min, int max, boolean notTarget) { - return new TargetCreaturePermanent(min, max).withNotTarget(notTarget); - } - static Target createImpossibleTarget(int min, int max) { return createImpossibleTarget(min, max, false); } @@ -71,4 +75,9 @@ abstract class BaseTestableDialog implements TestableDialog { private static Target createImpossibleTarget(int min, int max, boolean notTarget) { return new TargetCreaturePermanent(min, max, new FilterCreaturePermanent(SubType.TROOPER, "rare type"), notTarget); } + + @Override + public String toString() { + return this.getGroup() + " - " + this.getName() + " - " + this.getDescription(); + } } diff --git a/Mage.Common/src/main/java/mage/utils/testers/BaseTestableResult.java b/Mage.Common/src/main/java/mage/utils/testers/BaseTestableResult.java new file mode 100644 index 00000000000..ebca158ee9c --- /dev/null +++ b/Mage.Common/src/main/java/mage/utils/testers/BaseTestableResult.java @@ -0,0 +1,50 @@ +package mage.utils.testers; + +import java.util.ArrayList; +import java.util.List; + +/** + * Part of testable game dialogs + * + * @author JayDi85 + */ +public class BaseTestableResult implements TestableResult { + + boolean saved = false; + boolean status = false; + List info = new ArrayList<>(); + + @Override + public boolean getStatus() { + return this.status; + } + + @Override + public List getInfo() { + return this.info; + } + + @Override + public void save(boolean status, List info) { + this.saved = true; + this.status = status; + this.info = info; + } + + @Override + public boolean isOk() { + return true; + } + + @Override + public boolean isSaved() { + return this.saved; + } + + @Override + public void clear() { + this.saved = false; + this.status = false; + this.info.clear(); + } +} diff --git a/Mage.Common/src/main/java/mage/utils/testers/ChoiceTestableResult.java b/Mage.Common/src/main/java/mage/utils/testers/ChoiceTestableResult.java new file mode 100644 index 00000000000..ca6b1528558 --- /dev/null +++ b/Mage.Common/src/main/java/mage/utils/testers/ChoiceTestableResult.java @@ -0,0 +1,29 @@ +package mage.utils.testers; + +import java.util.List; + +/** + * Part of testable game dialogs + * + * @author JayDi85 + */ +public class ChoiceTestableResult extends BaseTestableResult { + + String choice = null; + + public void save(boolean status, List info, String choice) { + this.save(status, info); + this.choice = choice; + } + + @Override + public boolean isOk() { + return true; + } + + @Override + public void clear() { + super.clear(); + this.choice = null; + } +} diff --git a/Mage.Common/src/main/java/mage/utils/testers/ChooseAmountTestableDialog.java b/Mage.Common/src/main/java/mage/utils/testers/ChooseAmountTestableDialog.java index 6a7847ec4fc..8effb6cf43f 100644 --- a/Mage.Common/src/main/java/mage/utils/testers/ChooseAmountTestableDialog.java +++ b/Mage.Common/src/main/java/mage/utils/testers/ChooseAmountTestableDialog.java @@ -32,7 +32,8 @@ class ChooseAmountTestableDialog extends BaseTestableDialog { public ChooseAmountTestableDialog(boolean isYou, String name, int distributeAmount, int targetsMin, int targetsMax) { super(String.format("player.chooseTarget(%s, amount)", isYou ? "you" : "AI"), name, - String.format("%d between %d-%d targets", distributeAmount, targetsMin, targetsMax)); + String.format("%d between %d-%d targets", distributeAmount, targetsMin, targetsMax), + new TargetTestableResult()); this.isYou = isYou; this.distributeAmount = distributeAmount; this.targetsMin = targetsMin; @@ -40,19 +41,20 @@ class ChooseAmountTestableDialog extends BaseTestableDialog { } @Override - public List showDialog(Player player, Ability source, Game game, Player opponent) { + public void showDialog(Player player, Ability source, Game game, Player opponent) { TargetAmount choosingTarget = new TargetAnyTargetAmount(this.distributeAmount, this.targetsMin, this.targetsMax); Player choosingPlayer = this.isYou ? player : opponent; // TODO: add "damage" word in ability text, so chooseTargetAmount an show diff dialog (due inner logic - distribute damage or 1/1) boolean chooseRes = choosingPlayer.chooseTargetAmount(Outcome.Benefit, choosingTarget, source, game); - List result = new ArrayList<>(); + List res = new ArrayList<>(); if (chooseRes) { - Targets.printDebugTargets(getGroup() + " - " + this.getName() + " - " + "TRUE", new Targets(choosingTarget), source, game, result); + Targets.printDebugTargets(getGroup() + " - " + this.getName() + " - " + "TRUE", new Targets(choosingTarget), source, game, res); } else { - Targets.printDebugTargets(getGroup() + " - " + this.getName() + " - " + "FALSE", new Targets(choosingTarget), source, game, result); + Targets.printDebugTargets(getGroup() + " - " + this.getName() + " - " + "FALSE", new Targets(choosingTarget), source, game, res); } - return result; + + ((TargetTestableResult) this.getResult()).save(chooseRes, res, choosingTarget); } static public void register(TestableDialogsRunner runner) { diff --git a/Mage.Common/src/main/java/mage/utils/testers/ChooseCardsTestableDialog.java b/Mage.Common/src/main/java/mage/utils/testers/ChooseCardsTestableDialog.java index 8837d9b92ce..1d99b17cb82 100644 --- a/Mage.Common/src/main/java/mage/utils/testers/ChooseCardsTestableDialog.java +++ b/Mage.Common/src/main/java/mage/utils/testers/ChooseCardsTestableDialog.java @@ -36,16 +36,17 @@ class ChooseCardsTestableDialog extends BaseTestableDialog { public ChooseCardsTestableDialog(boolean isTargetChoice, boolean notTarget, boolean isYou, String name, TargetCard target) { super(String.format("%s(%s, %s, cards)", - isTargetChoice ? "player.chooseTarget" : "player.choose", - isYou ? "you" : "AI", - notTarget ? "not target" : "target"), name, target.toString()); + isTargetChoice ? "player.chooseTarget" : "player.choose", + isYou ? "you" : "AI", + notTarget ? "not target" : "target"), name, target.toString(), + new TargetTestableResult()); this.isTargetChoice = isTargetChoice; this.target = target.withNotTarget(notTarget); this.isYou = isYou; } @Override - public List showDialog(Player player, Ability source, Game game, Player opponent) { + public void showDialog(Player player, Ability source, Game game, Player opponent) { TargetCard choosingTarget = this.target.copy(); Player choosingPlayer = this.isYou ? player : opponent; @@ -62,13 +63,14 @@ class ChooseCardsTestableDialog extends BaseTestableDialog { chooseRes = choosingPlayer.choose(Outcome.Benefit, choosingCards, choosingTarget, source, game); } - List result = new ArrayList<>(); + List res = new ArrayList<>(); if (chooseRes) { - Targets.printDebugTargets(getGroup() + " - " + this.getName() + " - " + "TRUE", new Targets(choosingTarget), source, game, result); + Targets.printDebugTargets(getGroup() + " - " + this.getName() + " - " + "TRUE", new Targets(choosingTarget), source, game, res); } else { - Targets.printDebugTargets(getGroup() + " - " + this.getName() + " - " + "FALSE", new Targets(choosingTarget), source, game, result); + Targets.printDebugTargets(getGroup() + " - " + this.getName() + " - " + "FALSE", new Targets(choosingTarget), source, game, res); } - return result; + + ((TargetTestableResult) this.getResult()).save(chooseRes, res, choosingTarget); } static public void register(TestableDialogsRunner runner) { diff --git a/Mage.Common/src/main/java/mage/utils/testers/ChooseChoiceTestableDialog.java b/Mage.Common/src/main/java/mage/utils/testers/ChooseChoiceTestableDialog.java index 7e90c6cb124..fc634e9e360 100644 --- a/Mage.Common/src/main/java/mage/utils/testers/ChooseChoiceTestableDialog.java +++ b/Mage.Common/src/main/java/mage/utils/testers/ChooseChoiceTestableDialog.java @@ -24,28 +24,35 @@ class ChooseChoiceTestableDialog extends BaseTestableDialog { Choice choice; public ChooseChoiceTestableDialog(boolean isYou, String name, Choice choice) { - super(String.format("player.choose(%s, choice)", isYou ? "you" : "AI"), name, choice.getClass().getSimpleName()); + super(String.format("player.choose(%s, choice)", isYou ? "you" : "AI"), + name, + choice.getClass().getSimpleName(), + new ChoiceTestableResult() + ); this.isYou = isYou; this.choice = choice; } @Override - public List showDialog(Player player, Ability source, Game game, Player opponent) { + public void showDialog(Player player, Ability source, Game game, Player opponent) { Player choosingPlayer = this.isYou ? player : opponent; Choice dialog = this.choice.copy(); boolean chooseRes = choosingPlayer.choose(Outcome.Benefit, dialog, game); - List result = new ArrayList<>(); - result.add(getGroup() + " - " + this.getName() + " - " + (chooseRes ? "TRUE" : "FALSE")); - result.add(""); + List res = new ArrayList<>(); + res.add(getGroup() + " - " + this.getName() + " - " + (chooseRes ? "TRUE" : "FALSE")); + res.add(""); + String choice; if (dialog.isKeyChoice()) { String key = dialog.getChoiceKey(); - result.add(String.format("* selected key: %s (%s)", key, dialog.getKeyChoices().getOrDefault(key, null))); + choice = dialog.getKeyChoices().getOrDefault(key, null); + res.add(String.format("* selected key: %s (%s)", key, choice)); } else { - result.add(String.format("* selected value: %s", dialog.getChoice())); + choice = dialog.getChoice(); + res.add(String.format("* selected value: %s", choice)); } - return result; + ((ChoiceTestableResult) this.getResult()).save(chooseRes, res, choice); } static public void register(TestableDialogsRunner runner) { diff --git a/Mage.Common/src/main/java/mage/utils/testers/ChoosePileTestableDialog.java b/Mage.Common/src/main/java/mage/utils/testers/ChoosePileTestableDialog.java index 68bc9bbb265..35f79018a1c 100644 --- a/Mage.Common/src/main/java/mage/utils/testers/ChoosePileTestableDialog.java +++ b/Mage.Common/src/main/java/mage/utils/testers/ChoosePileTestableDialog.java @@ -28,14 +28,18 @@ class ChoosePileTestableDialog extends BaseTestableDialog { int pileSize2; public ChoosePileTestableDialog(boolean isYou, int pileSize1, int pileSize2) { - super(String.format("player.choosePile(%s)", isYou ? "you" : "AI"), "pile sizes: " + pileSize1 + " and " + pileSize2, ""); + super(String.format("player.choosePile(%s)", isYou ? "you" : "AI"), + "pile sizes: " + pileSize1 + " and " + pileSize2, + "", + new BaseTestableResult() + ); this.isYou = isYou; this.pileSize1 = pileSize1; this.pileSize2 = pileSize2; } @Override - public List showDialog(Player player, Ability source, Game game, Player opponent) { + public void showDialog(Player player, Ability source, Game game, Player opponent) { // TODO: it's ok to show broken title - must add html support in windows's title someday String mainMessage = "main message with html" + CardUtil.getSourceLogName(game, source); @@ -48,10 +52,11 @@ class ChoosePileTestableDialog extends BaseTestableDialog { Player choosingPlayer = this.isYou ? player : opponent; boolean chooseRes = choosingPlayer.choosePile(Outcome.Benefit, mainMessage, pile1, pile2, game); - List result = new ArrayList<>(); - result.add(getGroup() + " - " + this.getName() + " - " + (chooseRes ? "TRUE" : "FALSE")); - result.add(" * selected pile: " + (chooseRes ? "pile 1" : "pile 2")); - return result; + List res = new ArrayList<>(); + res.add(getGroup() + " - " + this.getName() + " - " + (chooseRes ? "TRUE" : "FALSE")); + res.add(" * selected pile: " + (chooseRes ? "pile 1" : "pile 2")); + + this.getResult().save(chooseRes, res); } static public void register(TestableDialogsRunner runner) { diff --git a/Mage.Common/src/main/java/mage/utils/testers/ChooseTargetTestableDialog.java b/Mage.Common/src/main/java/mage/utils/testers/ChooseTargetTestableDialog.java index 65284618774..2c7e5b7a0c2 100644 --- a/Mage.Common/src/main/java/mage/utils/testers/ChooseTargetTestableDialog.java +++ b/Mage.Common/src/main/java/mage/utils/testers/ChooseTargetTestableDialog.java @@ -31,10 +31,14 @@ class ChooseTargetTestableDialog extends BaseTestableDialog { public ChooseTargetTestableDialog(boolean isPlayerChoice, boolean isTargetChoice, boolean notTarget, boolean isYou, String name, Target target) { super(String.format("%s%s(%s, %s)", - isPlayerChoice ? "player.choose" : "target.choose", - isTargetChoice ? "Target" : "", // chooseTarget or choose - isYou ? "you" : "AI", - notTarget ? "not target" : "target"), name, target.toString()); + isPlayerChoice ? "player.choose" : "target.choose", + isTargetChoice ? "Target" : "", // chooseTarget or choose + isYou ? "you" : "AI", + notTarget ? "not target" : "target"), + name, + target.toString(), + new TargetTestableResult() + ); this.isPlayerChoice = isPlayerChoice; this.isTargetChoice = isTargetChoice; this.target = target.withNotTarget(notTarget); @@ -42,7 +46,7 @@ class ChooseTargetTestableDialog extends BaseTestableDialog { } @Override - public List showDialog(Player player, Ability source, Game game, Player opponent) { + public void showDialog(Player player, Ability source, Game game, Player opponent) { Target choosingTarget = this.target.copy(); Player choosingPlayer = this.isYou ? player : opponent; @@ -63,13 +67,22 @@ class ChooseTargetTestableDialog extends BaseTestableDialog { } } - List result = new ArrayList<>(); + List res = new ArrayList<>(); if (chooseRes) { - Targets.printDebugTargets(getGroup() + " - " + this.getName() + " - " + "TRUE", new Targets(choosingTarget), source, game, result); + Targets.printDebugTargets(getGroup() + " - " + this.getName() + " - " + "TRUE", new Targets(choosingTarget), source, game, res); } else { - Targets.printDebugTargets(getGroup() + " - " + this.getName() + " - " + "FALSE", new Targets(choosingTarget), source, game, result); + Targets.printDebugTargets(getGroup() + " - " + this.getName() + " - " + "FALSE", new Targets(choosingTarget), source, game, res); } - return result; + + ((TargetTestableResult) this.getResult()).save(chooseRes, res, choosingTarget); + } + + private ChooseTargetTestableDialog aiMustChoose(boolean status, int count) { + TargetTestableResult res = ((TargetTestableResult) this.getResult()); + res.aiAssert = true; + res.aiMustChooseStatus = status; + res.aiMustChooseTargetsCount = count; + return this; } static public void register(TestableDialogsRunner runner) { @@ -84,37 +97,29 @@ class ChooseTargetTestableDialog extends BaseTestableDialog { for (boolean isYou : isYous) { for (boolean isTargetChoice : isTargetChoices) { for (boolean isPlayerChoice : isPlayerChoices) { - runner.registerDialog(new ChooseTargetTestableDialog(isPlayerChoice, isTargetChoice, notTarget, isYou, "any 0 e.g. X=0", createAnyTarget(0, 0))); // simulate X=0 - runner.registerDialog(new ChooseTargetTestableDialog(isPlayerChoice, isTargetChoice, notTarget, isYou, "any 1", createAnyTarget(1, 1))); - runner.registerDialog(new ChooseTargetTestableDialog(isPlayerChoice, isTargetChoice, notTarget, isYou, "any 3", createAnyTarget(3, 3))); - runner.registerDialog(new ChooseTargetTestableDialog(isPlayerChoice, isTargetChoice, notTarget, isYou, "any 5", createAnyTarget(5, 5))); - runner.registerDialog(new ChooseTargetTestableDialog(isPlayerChoice, isTargetChoice, notTarget, isYou, "any max", createAnyTarget(0, Integer.MAX_VALUE))); - runner.registerDialog(new ChooseTargetTestableDialog(isPlayerChoice, isTargetChoice, notTarget, isYou, "any 0-1", createAnyTarget(0, 1))); - runner.registerDialog(new ChooseTargetTestableDialog(isPlayerChoice, isTargetChoice, notTarget, isYou, "any 0-3", createAnyTarget(0, 3))); - runner.registerDialog(new ChooseTargetTestableDialog(isPlayerChoice, isTargetChoice, notTarget, isYou, "any 0-5", createAnyTarget(0, 5))); - runner.registerDialog(new ChooseTargetTestableDialog(isPlayerChoice, isTargetChoice, notTarget, isYou, "any 1-3", createAnyTarget(1, 3))); - runner.registerDialog(new ChooseTargetTestableDialog(isPlayerChoice, isTargetChoice, notTarget, isYou, "any 2-3", createAnyTarget(2, 3))); - runner.registerDialog(new ChooseTargetTestableDialog(isPlayerChoice, isTargetChoice, notTarget, isYou, "any 1-5", createAnyTarget(1, 5))); - runner.registerDialog(new ChooseTargetTestableDialog(isPlayerChoice, isTargetChoice, notTarget, isYou, "any 2-5", createAnyTarget(2, 5))); - runner.registerDialog(new ChooseTargetTestableDialog(isPlayerChoice, isTargetChoice, notTarget, isYou, "any 3-5", createAnyTarget(3, 5))); - runner.registerDialog(new ChooseTargetTestableDialog(isPlayerChoice, isTargetChoice, notTarget, isYou, "any 4-5", createAnyTarget(4, 5))); // impossible on 3 targets + runner.registerDialog(new ChooseTargetTestableDialog(isPlayerChoice, isTargetChoice, notTarget, isYou, "any 0 e.g. X=0", createAnyTarget(0, 0)).aiMustChoose(true, 0)); // simulate X=0 + runner.registerDialog(new ChooseTargetTestableDialog(isPlayerChoice, isTargetChoice, notTarget, isYou, "any 1", createAnyTarget(1, 1)).aiMustChoose(true, 1)); + runner.registerDialog(new ChooseTargetTestableDialog(isPlayerChoice, isTargetChoice, notTarget, isYou, "any 3", createAnyTarget(3, 3)).aiMustChoose(true, 3)); + runner.registerDialog(new ChooseTargetTestableDialog(isPlayerChoice, isTargetChoice, notTarget, isYou, "any 5", createAnyTarget(5, 5)).aiMustChoose(true, 5)); + runner.registerDialog(new ChooseTargetTestableDialog(isPlayerChoice, isTargetChoice, notTarget, isYou, "any max", createAnyTarget(0, Integer.MAX_VALUE)).aiMustChoose(true, 0)); + runner.registerDialog(new ChooseTargetTestableDialog(isPlayerChoice, isTargetChoice, notTarget, isYou, "any 0-1", createAnyTarget(0, 1)).aiMustChoose(true, 1)); + runner.registerDialog(new ChooseTargetTestableDialog(isPlayerChoice, isTargetChoice, notTarget, isYou, "any 0-3", createAnyTarget(0, 3)).aiMustChoose(true, 3)); + runner.registerDialog(new ChooseTargetTestableDialog(isPlayerChoice, isTargetChoice, notTarget, isYou, "any 0-5", createAnyTarget(0, 5)).aiMustChoose(true, 5)); + runner.registerDialog(new ChooseTargetTestableDialog(isPlayerChoice, isTargetChoice, notTarget, isYou, "any 1-3", createAnyTarget(1, 3)).aiMustChoose(true, 3)); + runner.registerDialog(new ChooseTargetTestableDialog(isPlayerChoice, isTargetChoice, notTarget, isYou, "any 2-3", createAnyTarget(2, 3)).aiMustChoose(true, 3)); + runner.registerDialog(new ChooseTargetTestableDialog(isPlayerChoice, isTargetChoice, notTarget, isYou, "any 1-5", createAnyTarget(1, 5)).aiMustChoose(true, 5)); + runner.registerDialog(new ChooseTargetTestableDialog(isPlayerChoice, isTargetChoice, notTarget, isYou, "any 2-5", createAnyTarget(2, 5)).aiMustChoose(true, 5)); + runner.registerDialog(new ChooseTargetTestableDialog(isPlayerChoice, isTargetChoice, notTarget, isYou, "any 3-5", createAnyTarget(3, 5)).aiMustChoose(true, 5)); + runner.registerDialog(new ChooseTargetTestableDialog(isPlayerChoice, isTargetChoice, notTarget, isYou, "any 4-5", createAnyTarget(4, 5)).aiMustChoose(true, 5)); // impossible on 3 targets // - runner.registerDialog(new ChooseTargetTestableDialog(isPlayerChoice, isTargetChoice, notTarget, isYou, "impossible 0, e.g. X=0", createImpossibleTarget(0, 0))); - runner.registerDialog(new ChooseTargetTestableDialog(isPlayerChoice, isTargetChoice, notTarget, isYou, "impossible 1", createImpossibleTarget(1, 1))); - runner.registerDialog(new ChooseTargetTestableDialog(isPlayerChoice, isTargetChoice, notTarget, isYou, "impossible 3", createImpossibleTarget(3, 3))); - runner.registerDialog(new ChooseTargetTestableDialog(isPlayerChoice, isTargetChoice, notTarget, isYou, "impossible 0-1", createImpossibleTarget(0, 1))); - runner.registerDialog(new ChooseTargetTestableDialog(isPlayerChoice, isTargetChoice, notTarget, isYou, "impossible 0-3", createImpossibleTarget(0, 3))); - runner.registerDialog(new ChooseTargetTestableDialog(isPlayerChoice, isTargetChoice, notTarget, isYou, "impossible 1-3", createImpossibleTarget(1, 3))); - runner.registerDialog(new ChooseTargetTestableDialog(isPlayerChoice, isTargetChoice, notTarget, isYou, "impossible 2-3", createImpossibleTarget(2, 3))); - runner.registerDialog(new ChooseTargetTestableDialog(isPlayerChoice, isTargetChoice, notTarget, isYou, "impossible max", createImpossibleTarget(0, Integer.MAX_VALUE))); - // - /* - runner.registerDialog(new PlayerChooseTestableDialog(isPlayerChoice, isTargetChoice, notTarget, isYou, "creatures 0, e.g. X=0", createCreatureTarget(0, 0))); // simulate X=0 - runner.registerDialog(new PlayerChooseTestableDialog(isPlayerChoice, isTargetChoice, notTarget, isYou, "creatures 1", createCreatureTarget(1, 1))); - runner.registerDialog(new PlayerChooseTestableDialog(isPlayerChoice, isTargetChoice, notTarget, isYou, "creatures 3", createCreatureTarget(3, 3))); - runner.registerDialog(new PlayerChooseTestableDialog(isPlayerChoice, isTargetChoice, notTarget, isYou, "creatures 5", createCreatureTarget(5, 5))); - runner.registerDialog(new PlayerChooseTestableDialog(isPlayerChoice, isTargetChoice, notTarget, isYou, "creatures max", createCreatureTarget(0, Integer.MAX_VALUE))); - */ + runner.registerDialog(new ChooseTargetTestableDialog(isPlayerChoice, isTargetChoice, notTarget, isYou, "impossible 0, e.g. X=0", createImpossibleTarget(0, 0)).aiMustChoose(false, 0)); + runner.registerDialog(new ChooseTargetTestableDialog(isPlayerChoice, isTargetChoice, notTarget, isYou, "impossible 1", createImpossibleTarget(1, 1)).aiMustChoose(false, 0)); + runner.registerDialog(new ChooseTargetTestableDialog(isPlayerChoice, isTargetChoice, notTarget, isYou, "impossible 3", createImpossibleTarget(3, 3)).aiMustChoose(false, 0)); + runner.registerDialog(new ChooseTargetTestableDialog(isPlayerChoice, isTargetChoice, notTarget, isYou, "impossible 0-1", createImpossibleTarget(0, 1)).aiMustChoose(false, 0)); + runner.registerDialog(new ChooseTargetTestableDialog(isPlayerChoice, isTargetChoice, notTarget, isYou, "impossible 0-3", createImpossibleTarget(0, 3)).aiMustChoose(false, 0)); + runner.registerDialog(new ChooseTargetTestableDialog(isPlayerChoice, isTargetChoice, notTarget, isYou, "impossible 1-3", createImpossibleTarget(1, 3)).aiMustChoose(false, 0)); + runner.registerDialog(new ChooseTargetTestableDialog(isPlayerChoice, isTargetChoice, notTarget, isYou, "impossible 2-3", createImpossibleTarget(2, 3)).aiMustChoose(false, 0)); + runner.registerDialog(new ChooseTargetTestableDialog(isPlayerChoice, isTargetChoice, notTarget, isYou, "impossible max", createImpossibleTarget(0, Integer.MAX_VALUE)).aiMustChoose(false, 0)); } } } diff --git a/Mage.Common/src/main/java/mage/utils/testers/ChooseUseTestableDialog.java b/Mage.Common/src/main/java/mage/utils/testers/ChooseUseTestableDialog.java index 3e8137af32b..d56bb5718de 100644 --- a/Mage.Common/src/main/java/mage/utils/testers/ChooseUseTestableDialog.java +++ b/Mage.Common/src/main/java/mage/utils/testers/ChooseUseTestableDialog.java @@ -27,7 +27,11 @@ class ChooseUseTestableDialog extends BaseTestableDialog { String messageAdditional; public ChooseUseTestableDialog(boolean isYou, String name, String trueText, String falseText, String messageMain, String messageAdditional) { - super(String.format("player.chooseUse(%s)", isYou ? "you" : "AI"), name + buildName(trueText, falseText, messageMain, messageAdditional), ""); + super(String.format("player.chooseUse(%s)", isYou ? "you" : "AI"), + name + buildName(trueText, falseText, messageMain, messageAdditional), + "", + new BaseTestableResult() + ); this.isYou = isYou; this.trueText = trueText; this.falseText = falseText; @@ -42,7 +46,7 @@ class ChooseUseTestableDialog extends BaseTestableDialog { } @Override - public List showDialog(Player player, Ability source, Game game, Player opponent) { + public void showDialog(Player player, Ability source, Game game, Player opponent) { Player choosingPlayer = this.isYou ? player : opponent; boolean chooseRes = choosingPlayer.chooseUse( Outcome.Benefit, @@ -53,9 +57,10 @@ class ChooseUseTestableDialog extends BaseTestableDialog { source, game ); - List result = new ArrayList<>(); - result.add(chooseRes ? "TRUE" : "FALSE"); - return result; + List res = new ArrayList<>(); + res.add(chooseRes ? "TRUE" : "FALSE"); + + this.getResult().save(chooseRes, res); } static public void register(TestableDialogsRunner runner) { diff --git a/Mage.Common/src/main/java/mage/utils/testers/GetAmountTestableDialog.java b/Mage.Common/src/main/java/mage/utils/testers/GetAmountTestableDialog.java index 0a66bac8f9d..00bd15b26b3 100644 --- a/Mage.Common/src/main/java/mage/utils/testers/GetAmountTestableDialog.java +++ b/Mage.Common/src/main/java/mage/utils/testers/GetAmountTestableDialog.java @@ -26,21 +26,25 @@ class GetAmountTestableDialog extends BaseTestableDialog { public GetAmountTestableDialog(boolean isYou, int min, int max) { super(String.format("player.getAmount(%s)", isYou ? "you" : "AI"), - String.format("from %d to %d", min, max), ""); + String.format("from %d to %d", min, max), + "", + new AmountTestableResult() + ); this.isYou = isYou; this.min = min; this.max = max; } @Override - public List showDialog(Player player, Ability source, Game game, Player opponent) { + public void showDialog(Player player, Ability source, Game game, Player opponent) { Player choosingPlayer = this.isYou ? player : opponent; String message = "message with html"; int chooseRes; chooseRes = choosingPlayer.getAmount(this.min, this.max, message, source, game); - List result = new ArrayList<>(); - result.add(getGroup() + " - " + this.getName() + " selected " + chooseRes); - return result; + List res = new ArrayList<>(); + res.add(getGroup() + " - " + this.getName() + " selected " + chooseRes); + + ((AmountTestableResult) this.getResult()).save(true, res, chooseRes); } static public void register(TestableDialogsRunner runner) { diff --git a/Mage.Common/src/main/java/mage/utils/testers/GetMultiAmountTestableDialog.java b/Mage.Common/src/main/java/mage/utils/testers/GetMultiAmountTestableDialog.java index 2c1f9046f3a..6d30b105a0c 100644 --- a/Mage.Common/src/main/java/mage/utils/testers/GetMultiAmountTestableDialog.java +++ b/Mage.Common/src/main/java/mage/utils/testers/GetMultiAmountTestableDialog.java @@ -36,7 +36,9 @@ class GetMultiAmountTestableDialog extends BaseTestableDialog { public GetMultiAmountTestableDialog(boolean isYou, String info, int totalMin, int totalMax, List> options) { super(String.format("player.getMultiAmount(%s)", isYou ? "you" : "AI"), String.format("%s, %d options from [%d-%d]", info, options.size(), totalMin, totalMax), - ""); + "", + new MultiAmountTestableResult() + ); this.isYou = isYou; this.totalMin = totalMin; this.totalMax = totalMax; @@ -49,7 +51,7 @@ class GetMultiAmountTestableDialog extends BaseTestableDialog { } @Override - public List showDialog(Player player, Ability source, Game game, Player opponent) { + public void showDialog(Player player, Ability source, Game game, Player opponent) { Player choosingPlayer = this.isYou ? player : opponent; //String message = "message with html"; List chooseRes; @@ -63,24 +65,24 @@ class GetMultiAmountTestableDialog extends BaseTestableDialog { game ); - List result = new ArrayList<>(); - result.add(getGroup() + " - " + this.getName()); + List res = new ArrayList<>(); + res.add(getGroup() + " - " + this.getName()); int selectedIndex = -1; int selectedTotal = 0; for (Integer selectedValue : chooseRes) { selectedIndex++; selectedTotal += selectedValue; MultiAmountMessage option = this.amountOptions.get(selectedIndex); - result.add(String.format("%d from [%d-%d, def %d]", + res.add(String.format("%d from [%d-%d, def %d]", selectedValue, option.min, option.max, option.defaultValue )); } - result.add("total selected: " + selectedTotal); + res.add("total selected: " + selectedTotal); - return result; + ((MultiAmountTestableResult) this.getResult()).save(true, res, chooseRes); } static public void register(TestableDialogsRunner runner) { @@ -104,6 +106,7 @@ class GetMultiAmountTestableDialog extends BaseTestableDialog { runner.registerDialog(new GetMultiAmountTestableDialog(isYou, "many, 20 def", 60, 60, genSameOptions(3, 0, 60, 20))); // big lists runner.registerDialog(new GetMultiAmountTestableDialog(isYou, "big list", 0, 100, genSameOptions(20, 0, 100, 0))); + runner.registerDialog(new GetMultiAmountTestableDialog(isYou, "big list", 0, 100, genSameOptions(100, 0, 100, 0))); } } diff --git a/Mage.Common/src/main/java/mage/utils/testers/MultiAmountTestableResult.java b/Mage.Common/src/main/java/mage/utils/testers/MultiAmountTestableResult.java new file mode 100644 index 00000000000..c94fb4cf321 --- /dev/null +++ b/Mage.Common/src/main/java/mage/utils/testers/MultiAmountTestableResult.java @@ -0,0 +1,30 @@ +package mage.utils.testers; + +import java.util.ArrayList; +import java.util.List; + +/** + * Part of testable game dialogs + * + * @author JayDi85 + */ +public class MultiAmountTestableResult extends BaseTestableResult { + + List values = new ArrayList<>(); + + public void save(boolean status, List info, List values) { + this.save(status, info); + this.values = values; + } + + @Override + public boolean isOk() { + return true; + } + + @Override + public void clear() { + super.clear(); + this.values.clear(); + } +} diff --git a/Mage.Common/src/main/java/mage/utils/testers/TargetTestableResult.java b/Mage.Common/src/main/java/mage/utils/testers/TargetTestableResult.java new file mode 100644 index 00000000000..b44e8cfa20a --- /dev/null +++ b/Mage.Common/src/main/java/mage/utils/testers/TargetTestableResult.java @@ -0,0 +1,55 @@ +package mage.utils.testers; + +import mage.target.Target; + +import java.util.List; + +/** + * Part of testable game dialogs + * + * @author JayDi85 + */ +public class TargetTestableResult extends BaseTestableResult { + + Target target = null; + + boolean aiAssert = false; + boolean aiMustChooseStatus = false; + int aiMustChooseTargetsCount = 0; + + public void save(boolean status, List info, Target target) { + this.save(status, info); + this.target = target; + } + + @Override + public boolean isOk() { + if (!this.aiAssert) { + return true; + } + + // not finish + if (this.target == null) { + return false; + } + + // wrong choose + if (this.getStatus() != this.aiMustChooseStatus) { + return false; + } + + // wrong targets + if (this.target.getTargets().size() != this.aiMustChooseTargetsCount) { + return false; + } + + // all fine + return true; + } + + @Override + public void clear() { + super.clear(); + this.target = null; + } +} diff --git a/Mage.Common/src/main/java/mage/utils/testers/TestableDialog.java b/Mage.Common/src/main/java/mage/utils/testers/TestableDialog.java index 1479ee9f306..533eb1fc33e 100644 --- a/Mage.Common/src/main/java/mage/utils/testers/TestableDialog.java +++ b/Mage.Common/src/main/java/mage/utils/testers/TestableDialog.java @@ -4,8 +4,6 @@ import mage.abilities.Ability; import mage.game.Game; import mage.players.Player; -import java.util.List; - /** * Part of testable game dialogs *

@@ -17,7 +15,7 @@ import java.util.List; * * @author JayDi85 */ -interface TestableDialog { +public interface TestableDialog { String getGroup(); @@ -25,7 +23,20 @@ interface TestableDialog { String getDescription(); - List showDialog(Player player, Ability source, Game game, Player opponent); + TestableResult getResult(); - void showResult(Player player, Game game, String result); + /** + * Prepare dialog before show, e.g. clear prev results + */ + void prepare(); + + /** + * Show game dialog to the user and save result + */ + void showDialog(Player player, Ability source, Game game, Player opponent); + + /** + * Show result dialog to the user + */ + void showResult(Player player, Game game); } diff --git a/Mage.Common/src/main/java/mage/utils/testers/TestableDialogsRunner.java b/Mage.Common/src/main/java/mage/utils/testers/TestableDialogsRunner.java index 3c2cfb3840d..3e2bc463eb7 100644 --- a/Mage.Common/src/main/java/mage/utils/testers/TestableDialogsRunner.java +++ b/Mage.Common/src/main/java/mage/utils/testers/TestableDialogsRunner.java @@ -129,8 +129,9 @@ public class TestableDialogsRunner { // all fine, can show it and finish lastSelectedGroup = needGroup; lastSelectedDialog = needDialog; - List resInfo = needDialog.showDialog(player, source, game, opponent); - needDialog.showResult(player, game, String.join("
", resInfo)); + needDialog.prepare(); + needDialog.showDialog(player, source, game, opponent); + needDialog.showResult(player, game); } private Choice prepareSelectGroupChoice(List groups) { @@ -199,5 +200,9 @@ public class TestableDialogsRunner { } return choice; } + + public List getDialogs() { + return this.dialogs; + } } diff --git a/Mage.Common/src/main/java/mage/utils/testers/TestableResult.java b/Mage.Common/src/main/java/mage/utils/testers/TestableResult.java new file mode 100644 index 00000000000..d0a28a7bd7c --- /dev/null +++ b/Mage.Common/src/main/java/mage/utils/testers/TestableResult.java @@ -0,0 +1,29 @@ +package mage.utils.testers; + +import java.util.List; + +/** + * Part of testable game dialogs, must contain dialogs result + * + * @author JayDi85 + */ +public interface TestableResult { + + boolean getStatus(); + + List getInfo(); + + /** + * Save new result after show dialog + * + * @param status result of choice dialog call + * @param info detail result to show in GUI + */ + void save(boolean status, List info); + + boolean isSaved(); + + void clear(); + + boolean isOk(); +} diff --git a/Mage.Tests/src/test/java/org/mage/test/dialogs/TestableDialogsTest.java b/Mage.Tests/src/test/java/org/mage/test/dialogs/TestableDialogsTest.java new file mode 100644 index 00000000000..231284a8ad0 --- /dev/null +++ b/Mage.Tests/src/test/java/org/mage/test/dialogs/TestableDialogsTest.java @@ -0,0 +1,166 @@ +package org.mage.test.dialogs; + +import mage.abilities.Ability; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.common.InfoEffect; +import mage.constants.PhaseStep; +import mage.constants.Zone; +import mage.utils.testers.TestableDialog; +import mage.utils.testers.TestableDialogsRunner; +import org.junit.Assert; +import org.junit.Test; +import org.mage.test.player.TestPlayer; +import org.mage.test.serverside.base.CardTestPlayerBaseWithAIHelps; + +import java.util.Collections; +import java.util.List; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.stream.Collectors; + +/** + * Try to test all possible game dialogs by TestableDialogsRunner + * + * TODO: fill ai results for all generated dialogs + * + * @author JayDi85 + */ +public class TestableDialogsTest extends CardTestPlayerBaseWithAIHelps { + + TestableDialogsRunner runner = new TestableDialogsRunner(); + Ability fakeAbility = new SimpleStaticAbility(new InfoEffect("fake")); + + @Test + public void test_RunSingle_Manual() { + addCard(Zone.BATTLEFIELD, playerA, "Mountain", 6); + addCard(Zone.HAND, playerA, "Forest", 6); + + runCode("run single", 1, PhaseStep.PRECOMBAT_MAIN, playerA, (info, player, game) -> { + TestableDialog dialog = findDialogs(runner, "target.choose(you, target)", "any 0-3").get(0); + Assert.assertNotNull(dialog); + dialog.prepare(); + dialog.showDialog(playerA, fakeAbility, game, playerB); + }); + + // choice for 0-3 + setChoice(playerA, "Mountain"); + setChoice(playerA, "Mountain"); + setChoice(playerA, TestPlayer.CHOICE_SKIP); + + setStrictChooseMode(true); + setStopAt(1, PhaseStep.END_TURN); + execute(); + + printRunnerResults(false); + } + + @Test + public void test_RunSingle_AI() { + addCard(Zone.BATTLEFIELD, playerA, "Mountain", 6); + addCard(Zone.HAND, playerA, "Forest", 6); + + aiPlayStep(1, PhaseStep.PRECOMBAT_MAIN, PhaseStep.END_TURN, playerA); + aiPlayStep(1, PhaseStep.PRECOMBAT_MAIN, PhaseStep.END_TURN, playerB); + runCode("run single", 1, PhaseStep.POSTCOMBAT_MAIN, playerA, (info, player, game) -> { + TestableDialog dialog = findDialogs(runner, "target.choose(you, target)", "any 0-3").get(0); + Assert.assertNotNull(dialog); + dialog.prepare(); + dialog.showDialog(playerA, fakeAbility, game, playerB); + }); + + setStrictChooseMode(true); + setStopAt(1, PhaseStep.END_TURN); + execute(); + + printRunnerResults(false); + } + + @Test + public void test_RunAll_AI() { + // it's impossible to setup 700+ dialogs, so all choices made by AI + // current AI uses only simple choices in dialogs, not simulations + + addCard(Zone.BATTLEFIELD, playerA, "Mountain", 6); + addCard(Zone.HAND, playerA, "Forest", 6); + + aiPlayStep(1, PhaseStep.PRECOMBAT_MAIN, PhaseStep.END_TURN, playerA); + aiPlayStep(1, PhaseStep.PRECOMBAT_MAIN, PhaseStep.END_TURN, playerB); + AtomicInteger dialogNumber = new AtomicInteger(); + runCode("run all", 1, PhaseStep.POSTCOMBAT_MAIN, playerA, (info, player, game) -> { + runner.getDialogs().forEach(dialog -> { + dialogNumber.incrementAndGet(); + System.out.println(String.format("run testable dialog %d of %d (%s, %s - %s)", + dialogNumber.get(), + runner.getDialogs().size(), + dialog.getClass().getSimpleName(), + dialog.getGroup(), + dialog.getName() + )); + dialog.showDialog(playerA, fakeAbility, game, playerB); + }); + }); + + setStrictChooseMode(true); + setStopAt(1, PhaseStep.END_TURN); + execute(); + + printRunnerResults(true); + } + + private List findDialogs(TestableDialogsRunner runner, String byGroup, String byName) { + return runner.getDialogs().stream() + .filter(d -> d.getGroup().equals(byGroup)) + .filter(d -> d.getName().equals(byName)) + .collect(Collectors.toList()); + } + + private void printRunnerResults(boolean showFullList) { + // print text table with full dialogs list and results + + // found table sizes + int maxGroupLength = "Group".length(); + int maxNameLength = "Name".length(); + for (TestableDialog dialog : runner.getDialogs()) { + if (!showFullList && !dialog.getResult().isSaved()) { + continue; + } + maxGroupLength = Math.max(maxGroupLength, dialog.getGroup().length()); + maxNameLength = Math.max(maxNameLength, dialog.getName().length()); + } + int maxResultLength = "Result".length(); + + String rowFormat = "| %-" + maxGroupLength + "s | %-" + maxNameLength + "s | %-" + maxResultLength + "s |%n"; + String horizontalBorder = "+-" + + String.join("", Collections.nCopies(maxGroupLength, "-")) + "-+-" + + String.join("", Collections.nCopies(maxNameLength, "-")) + "-+-" + + String.join("", Collections.nCopies(maxResultLength, "-")) + "-+"; + + // header + System.out.println(horizontalBorder); + System.out.printf(rowFormat, "Group", "Name", "Result"); + System.out.println(horizontalBorder); + + // data + String prevGroup = ""; + int totalDialogs = 0; + for (TestableDialog dialog : runner.getDialogs()) { + if (!showFullList && !dialog.getResult().isSaved()) { + continue; + } + totalDialogs++; + if (!prevGroup.isEmpty() && !prevGroup.equals(dialog.getGroup())) { + System.out.println(horizontalBorder); + } + prevGroup = dialog.getGroup(); + String status = dialog.getResult().isOk() ? "OK" : "FAIL"; + System.out.printf(rowFormat, dialog.getGroup(), dialog.getName(), status); + } + System.out.println(horizontalBorder); + + // totals + System.out.printf("| %-" + (maxGroupLength + maxNameLength + maxResultLength + 6) + "s |%n", + "Total dialogs: " + totalDialogs); + System.out.printf("| %-" + (maxGroupLength + maxNameLength + maxResultLength + 6) + "s |%n", + "Total results: TODO"); + System.out.println(horizontalBorder); + } +} \ No newline at end of file