tests: added automated tests to run all possible dialogs under AI (WIP, part of #13643, improved testable dialogs from #13638);

This commit is contained in:
Oleg Agafonov 2025-06-14 16:20:24 +04:00
parent 6ad2cdaa78
commit 361c320890
19 changed files with 555 additions and 107 deletions

View file

@ -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<String> 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;
}
}

View file

@ -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<String> 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 = "<font color=green>message</font> with html";
int chooseRes;
chooseRes = choosingPlayer.announceX(this.min, this.max, message, game, source, this.isMana);
List<String> result = new ArrayList<>();
result.add(getGroup() + " - " + this.getName() + " selected " + chooseRes);
return result;
List<String> res = new ArrayList<>();
res.add(getGroup() + " - " + this.getName() + " selected " + chooseRes);
((AmountTestableResult) this.getResult()).save(true, res, chooseRes);
}
static public void register(TestableDialogsRunner runner) {

View file

@ -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("<br>", 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();
}
}

View file

@ -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<String> info = new ArrayList<>();
@Override
public boolean getStatus() {
return this.status;
}
@Override
public List<String> getInfo() {
return this.info;
}
@Override
public void save(boolean status, List<String> 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();
}
}

View file

@ -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<String> 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;
}
}

View file

@ -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<String> 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<String> result = new ArrayList<>();
List<String> 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) {

View file

@ -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<String> 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<String> result = new ArrayList<>();
List<String> 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) {

View file

@ -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<String> 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<String> result = new ArrayList<>();
result.add(getGroup() + " - " + this.getName() + " - " + (chooseRes ? "TRUE" : "FALSE"));
result.add("");
List<String> 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) {

View file

@ -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<String> 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 <font color=green>message</font> 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<String> result = new ArrayList<>();
result.add(getGroup() + " - " + this.getName() + " - " + (chooseRes ? "TRUE" : "FALSE"));
result.add(" * selected pile: " + (chooseRes ? "pile 1" : "pile 2"));
return result;
List<String> 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) {

View file

@ -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<String> 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<String> result = new ArrayList<>();
List<String> 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));
}
}
}

View file

@ -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<String> 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<String> result = new ArrayList<>();
result.add(chooseRes ? "TRUE" : "FALSE");
return result;
List<String> res = new ArrayList<>();
res.add(chooseRes ? "TRUE" : "FALSE");
this.getResult().save(chooseRes, res);
}
static public void register(TestableDialogsRunner runner) {

View file

@ -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<String> 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 = "<font color=green>message</font> with html";
int chooseRes;
chooseRes = choosingPlayer.getAmount(this.min, this.max, message, source, game);
List<String> result = new ArrayList<>();
result.add(getGroup() + " - " + this.getName() + " selected " + chooseRes);
return result;
List<String> res = new ArrayList<>();
res.add(getGroup() + " - " + this.getName() + " selected " + chooseRes);
((AmountTestableResult) this.getResult()).save(true, res, chooseRes);
}
static public void register(TestableDialogsRunner runner) {

View file

@ -36,7 +36,9 @@ class GetMultiAmountTestableDialog extends BaseTestableDialog {
public GetMultiAmountTestableDialog(boolean isYou, String info, int totalMin, int totalMax, List<List<Integer>> 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<String> 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 = "<font color=green>message</font> with html";
List<Integer> chooseRes;
@ -63,24 +65,24 @@ class GetMultiAmountTestableDialog extends BaseTestableDialog {
game
);
List<String> result = new ArrayList<>();
result.add(getGroup() + " - " + this.getName());
List<String> 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)));
}
}

View file

@ -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<Integer> values = new ArrayList<>();
public void save(boolean status, List<String> info, List<Integer> values) {
this.save(status, info);
this.values = values;
}
@Override
public boolean isOk() {
return true;
}
@Override
public void clear() {
super.clear();
this.values.clear();
}
}

View file

@ -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<String> 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;
}
}

View file

@ -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
* <p>
@ -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<String> 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);
}

View file

@ -129,8 +129,9 @@ public class TestableDialogsRunner {
// all fine, can show it and finish
lastSelectedGroup = needGroup;
lastSelectedDialog = needDialog;
List<String> resInfo = needDialog.showDialog(player, source, game, opponent);
needDialog.showResult(player, game, String.join("<br>", resInfo));
needDialog.prepare();
needDialog.showDialog(player, source, game, opponent);
needDialog.showResult(player, game);
}
private Choice prepareSelectGroupChoice(List<String> groups) {
@ -199,5 +200,9 @@ public class TestableDialogsRunner {
}
return choice;
}
public List<TestableDialog> getDialogs() {
return this.dialogs;
}
}

View file

@ -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<String> 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<String> info);
boolean isSaved();
void clear();
boolean isOk();
}

View file

@ -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<TestableDialog> 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);
}
}