tests: improved testable dialogs with better/colored logs and asserts (part of #13643, #13638);

This commit is contained in:
Oleg Agafonov 2025-06-14 21:10:32 +04:00
parent d43e96eaf2
commit a98f72649a
17 changed files with 123 additions and 83 deletions

View file

@ -11,19 +11,19 @@ public class AmountTestableResult extends BaseTestableResult {
int amount = 0; int amount = 0;
public void save(boolean status, List<String> info, int amount) { public void onFinish(boolean status, List<String> info, int amount) {
this.save(status, info); this.onFinish(status, info);
this.amount = amount; this.amount = amount;
} }
@Override @Override
public boolean isOk() { public Boolean getResAssert() {
return true; return null; // TODO: implement
} }
@Override @Override
public void clear() { public void onClear() {
super.clear(); super.onClear();
this.amount = 0; this.amount = 0;
} }
} }

View file

@ -42,7 +42,7 @@ class AnnounceXTestableDialog extends BaseTestableDialog {
List<String> res = new ArrayList<>(); List<String> res = new ArrayList<>();
res.add(getGroup() + " - " + this.getName() + " selected " + chooseRes); res.add(getGroup() + " - " + this.getName() + " selected " + chooseRes);
((AmountTestableResult) this.getResult()).save(true, res, chooseRes); ((AmountTestableResult) this.getResult()).onFinish(true, res, chooseRes);
} }
static public void register(TestableDialogsRunner runner) { static public void register(TestableDialogsRunner runner) {

View file

@ -44,13 +44,13 @@ abstract class BaseTestableDialog implements TestableDialog {
@Override @Override
public void prepare() { public void prepare() {
this.result.clear(); this.result.onClear();
} }
@Override @Override
final public void showResult(Player player, Game game) { final public void showResult(Player player, Game game) {
// show message with result // show message with result
game.informPlayer(player, String.join("<br>", getResult().getInfo())); game.informPlayer(player, String.join("<br>", getResult().getResDetails()));
// reset game and gui (in most use cases it must return to player's priority) // reset game and gui (in most use cases it must return to player's priority)
game.firePriorityEvent(player.getId()); game.firePriorityEvent(player.getId());
} }

View file

@ -10,41 +10,41 @@ import java.util.List;
*/ */
public class BaseTestableResult implements TestableResult { public class BaseTestableResult implements TestableResult {
boolean saved = false; boolean isFinished = false;
boolean status = false; boolean resStatus = false;
List<String> info = new ArrayList<>(); List<String> resInfo = new ArrayList<>();
@Override @Override
public boolean getStatus() { public boolean getResStatus() {
return this.status; return this.resStatus;
} }
@Override @Override
public List<String> getInfo() { public List<String> getResDetails() {
return this.info; return this.resInfo;
} }
@Override @Override
public void save(boolean status, List<String> info) { public Boolean getResAssert() {
this.saved = true; return null; // TODO: implement
this.status = status;
this.info = info;
} }
@Override @Override
public boolean isOk() { public void onFinish(boolean resStatus, List<String> resDetails) {
return true; this.isFinished = true;
this.resStatus = resStatus;
this.resInfo = resDetails;
} }
@Override @Override
public boolean isSaved() { public boolean isFinished() {
return this.saved; return this.isFinished;
} }
@Override @Override
public void clear() { public void onClear() {
this.saved = false; this.isFinished = false;
this.status = false; this.resStatus = false;
this.info.clear(); this.resInfo.clear();
} }
} }

View file

@ -11,19 +11,19 @@ public class ChoiceTestableResult extends BaseTestableResult {
String choice = null; String choice = null;
public void save(boolean status, List<String> info, String choice) { public void onFinish(boolean status, List<String> info, String choice) {
this.save(status, info); this.onFinish(status, info);
this.choice = choice; this.choice = choice;
} }
@Override @Override
public boolean isOk() { public Boolean getResAssert() {
return true; return null; // TODO: implement
} }
@Override @Override
public void clear() { public void onClear() {
super.clear(); super.onClear();
this.choice = null; this.choice = null;
} }
} }

View file

@ -54,7 +54,7 @@ class ChooseAmountTestableDialog extends BaseTestableDialog {
Targets.printDebugTargets(getGroup() + " - " + this.getName() + " - " + "FALSE", new Targets(choosingTarget), source, game, res); Targets.printDebugTargets(getGroup() + " - " + this.getName() + " - " + "FALSE", new Targets(choosingTarget), source, game, res);
} }
((TargetTestableResult) this.getResult()).save(chooseRes, res, choosingTarget); ((TargetTestableResult) this.getResult()).onFinish(chooseRes, res, choosingTarget);
} }
static public void register(TestableDialogsRunner runner) { static public void register(TestableDialogsRunner runner) {

View file

@ -70,7 +70,7 @@ class ChooseCardsTestableDialog extends BaseTestableDialog {
Targets.printDebugTargets(getGroup() + " - " + this.getName() + " - " + "FALSE", new Targets(choosingTarget), source, game, res); Targets.printDebugTargets(getGroup() + " - " + this.getName() + " - " + "FALSE", new Targets(choosingTarget), source, game, res);
} }
((TargetTestableResult) this.getResult()).save(chooseRes, res, choosingTarget); ((TargetTestableResult) this.getResult()).onFinish(chooseRes, res, choosingTarget);
} }
static public void register(TestableDialogsRunner runner) { static public void register(TestableDialogsRunner runner) {

View file

@ -52,7 +52,7 @@ class ChooseChoiceTestableDialog extends BaseTestableDialog {
res.add(String.format("* selected value: %s", choice)); res.add(String.format("* selected value: %s", choice));
} }
((ChoiceTestableResult) this.getResult()).save(chooseRes, res, choice); ((ChoiceTestableResult) this.getResult()).onFinish(chooseRes, res, choice);
} }
static public void register(TestableDialogsRunner runner) { static public void register(TestableDialogsRunner runner) {

View file

@ -56,7 +56,7 @@ class ChoosePileTestableDialog extends BaseTestableDialog {
res.add(getGroup() + " - " + this.getName() + " - " + (chooseRes ? "TRUE" : "FALSE")); res.add(getGroup() + " - " + this.getName() + " - " + (chooseRes ? "TRUE" : "FALSE"));
res.add(" * selected pile: " + (chooseRes ? "pile 1" : "pile 2")); res.add(" * selected pile: " + (chooseRes ? "pile 1" : "pile 2"));
this.getResult().save(chooseRes, res); this.getResult().onFinish(chooseRes, res);
} }
static public void register(TestableDialogsRunner runner) { static public void register(TestableDialogsRunner runner) {

View file

@ -74,14 +74,14 @@ class ChooseTargetTestableDialog extends BaseTestableDialog {
Targets.printDebugTargets(getGroup() + " - " + this.getName() + " - " + "FALSE", new Targets(choosingTarget), source, game, res); Targets.printDebugTargets(getGroup() + " - " + this.getName() + " - " + "FALSE", new Targets(choosingTarget), source, game, res);
} }
((TargetTestableResult) this.getResult()).save(chooseRes, res, choosingTarget); ((TargetTestableResult) this.getResult()).onFinish(chooseRes, res, choosingTarget);
} }
private ChooseTargetTestableDialog aiMustChoose(boolean status, int count) { private ChooseTargetTestableDialog aiMustChoose(boolean resStatus, int targetsCount) {
TargetTestableResult res = ((TargetTestableResult) this.getResult()); TargetTestableResult res = ((TargetTestableResult) this.getResult());
res.aiAssert = true; res.aiAssertEnabled = true;
res.aiMustChooseStatus = status; res.aiAssertResStatus = resStatus;
res.aiMustChooseTargetsCount = count; res.aiAssertTargetsCount = targetsCount;
return this; return this;
} }

View file

@ -60,7 +60,7 @@ class ChooseUseTestableDialog extends BaseTestableDialog {
List<String> res = new ArrayList<>(); List<String> res = new ArrayList<>();
res.add(chooseRes ? "TRUE" : "FALSE"); res.add(chooseRes ? "TRUE" : "FALSE");
this.getResult().save(chooseRes, res); this.getResult().onFinish(chooseRes, res);
} }
static public void register(TestableDialogsRunner runner) { static public void register(TestableDialogsRunner runner) {

View file

@ -44,7 +44,7 @@ class GetAmountTestableDialog extends BaseTestableDialog {
List<String> res = new ArrayList<>(); List<String> res = new ArrayList<>();
res.add(getGroup() + " - " + this.getName() + " selected " + chooseRes); res.add(getGroup() + " - " + this.getName() + " selected " + chooseRes);
((AmountTestableResult) this.getResult()).save(true, res, chooseRes); ((AmountTestableResult) this.getResult()).onFinish(true, res, chooseRes);
} }
static public void register(TestableDialogsRunner runner) { static public void register(TestableDialogsRunner runner) {

View file

@ -82,7 +82,7 @@ class GetMultiAmountTestableDialog extends BaseTestableDialog {
} }
res.add("total selected: " + selectedTotal); res.add("total selected: " + selectedTotal);
((MultiAmountTestableResult) this.getResult()).save(true, res, chooseRes); ((MultiAmountTestableResult) this.getResult()).onFinish(true, res, chooseRes);
} }
static public void register(TestableDialogsRunner runner) { static public void register(TestableDialogsRunner runner) {

View file

@ -12,19 +12,19 @@ public class MultiAmountTestableResult extends BaseTestableResult {
List<Integer> values = new ArrayList<>(); List<Integer> values = new ArrayList<>();
public void save(boolean status, List<String> info, List<Integer> values) { public void onFinish(boolean status, List<String> info, List<Integer> values) {
this.save(status, info); this.onFinish(status, info);
this.values = values; this.values = values;
} }
@Override @Override
public boolean isOk() { public Boolean getResAssert() {
return true; return null; // TODO: implement
} }
@Override @Override
public void clear() { public void onClear() {
super.clear(); super.onClear();
this.values.clear(); this.values.clear();
} }
} }

View file

@ -13,33 +13,33 @@ public class TargetTestableResult extends BaseTestableResult {
Target target = null; Target target = null;
boolean aiAssert = false; boolean aiAssertEnabled = false;
boolean aiMustChooseStatus = false; boolean aiAssertResStatus = false;
int aiMustChooseTargetsCount = 0; int aiAssertTargetsCount = 0;
public void save(boolean status, List<String> info, Target target) { public void onFinish(boolean status, List<String> info, Target target) {
this.save(status, info); this.onFinish(status, info);
this.target = target; this.target = target;
} }
@Override @Override
public boolean isOk() { public Boolean getResAssert() {
if (!this.aiAssert) { if (!this.aiAssertEnabled) {
return true; return null;
} }
// not finish // not finished
if (this.target == null) { if (this.target == null) {
return false; return null;
} }
// wrong choose // wrong choose
if (this.getStatus() != this.aiMustChooseStatus) { if (this.getResStatus() != this.aiAssertResStatus) {
return false; return false;
} }
// wrong targets // wrong targets
if (this.target.getTargets().size() != this.aiMustChooseTargetsCount) { if (this.target.getTargets().size() != this.aiAssertTargetsCount) {
return false; return false;
} }
@ -48,8 +48,8 @@ public class TargetTestableResult extends BaseTestableResult {
} }
@Override @Override
public void clear() { public void onClear() {
super.clear(); super.onClear();
this.target = null; this.target = null;
} }
} }

View file

@ -9,21 +9,25 @@ import java.util.List;
*/ */
public interface TestableResult { public interface TestableResult {
boolean getStatus(); /**
* Dialog's result
*/
boolean getResStatus();
List<String> getInfo(); /**
* Dialog's detail result
*/
List<String> getResDetails();
/** /**
* Save new result after show dialog * 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); void onFinish(boolean resStatus, List<String> resDetails);
boolean isSaved(); boolean isFinished();
void clear(); void onClear();
boolean isOk(); Boolean getResAssert();
} }

View file

@ -8,6 +8,7 @@ import mage.constants.Zone;
import mage.utils.testers.TestableDialog; import mage.utils.testers.TestableDialog;
import mage.utils.testers.TestableDialogsRunner; import mage.utils.testers.TestableDialogsRunner;
import org.junit.Assert; import org.junit.Assert;
import org.junit.Ignore;
import org.junit.Test; import org.junit.Test;
import org.mage.test.player.TestPlayer; import org.mage.test.player.TestPlayer;
import org.mage.test.serverside.base.CardTestPlayerBaseWithAIHelps; import org.mage.test.serverside.base.CardTestPlayerBaseWithAIHelps;
@ -19,7 +20,7 @@ import java.util.stream.Collectors;
/** /**
* Try to test all possible game dialogs by TestableDialogsRunner * Try to test all possible game dialogs by TestableDialogsRunner
* * <p>
* TODO: fill ai results for all generated dialogs * TODO: fill ai results for all generated dialogs
* *
* @author JayDi85 * @author JayDi85
@ -50,7 +51,7 @@ public class TestableDialogsTest extends CardTestPlayerBaseWithAIHelps {
setStopAt(1, PhaseStep.END_TURN); setStopAt(1, PhaseStep.END_TURN);
execute(); execute();
printRunnerResults(false); printRunnerResults(false, false);
} }
@Test @Test
@ -71,10 +72,11 @@ public class TestableDialogsTest extends CardTestPlayerBaseWithAIHelps {
setStopAt(1, PhaseStep.END_TURN); setStopAt(1, PhaseStep.END_TURN);
execute(); execute();
printRunnerResults(false); printRunnerResults(false, true);
} }
@Test @Test
@Ignore // TODO: enable and fix all failed dialogs
public void test_RunAll_AI() { public void test_RunAll_AI() {
// it's impossible to setup 700+ dialogs, so all choices made by AI // it's impossible to setup 700+ dialogs, so all choices made by AI
// current AI uses only simple choices in dialogs, not simulations // current AI uses only simple choices in dialogs, not simulations
@ -103,7 +105,7 @@ public class TestableDialogsTest extends CardTestPlayerBaseWithAIHelps {
setStopAt(1, PhaseStep.END_TURN); setStopAt(1, PhaseStep.END_TURN);
execute(); execute();
printRunnerResults(true); printRunnerResults(true, true);
} }
private List<TestableDialog> findDialogs(TestableDialogsRunner runner, String byGroup, String byName) { private List<TestableDialog> findDialogs(TestableDialogsRunner runner, String byGroup, String byName) {
@ -113,14 +115,14 @@ public class TestableDialogsTest extends CardTestPlayerBaseWithAIHelps {
.collect(Collectors.toList()); .collect(Collectors.toList());
} }
private void printRunnerResults(boolean showFullList) { private void printRunnerResults(boolean showFullList, boolean assertGoodResults) {
// print text table with full dialogs list and results // print text table with full dialogs list and results
// found table sizes // found table sizes
int maxGroupLength = "Group".length(); int maxGroupLength = "Group".length();
int maxNameLength = "Name".length(); int maxNameLength = "Name".length();
for (TestableDialog dialog : runner.getDialogs()) { for (TestableDialog dialog : runner.getDialogs()) {
if (!showFullList && !dialog.getResult().isSaved()) { if (!showFullList && !dialog.getResult().isFinished()) {
continue; continue;
} }
maxGroupLength = Math.max(maxGroupLength, dialog.getGroup().length()); maxGroupLength = Math.max(maxGroupLength, dialog.getGroup().length());
@ -142,8 +144,11 @@ public class TestableDialogsTest extends CardTestPlayerBaseWithAIHelps {
// data // data
String prevGroup = ""; String prevGroup = "";
int totalDialogs = 0; int totalDialogs = 0;
int totalGood = 0;
int totalBad = 0;
int totalUnknown = 0;
for (TestableDialog dialog : runner.getDialogs()) { for (TestableDialog dialog : runner.getDialogs()) {
if (!showFullList && !dialog.getResult().isSaved()) { if (!showFullList && !dialog.getResult().isFinished()) {
continue; continue;
} }
totalDialogs++; totalDialogs++;
@ -151,7 +156,17 @@ public class TestableDialogsTest extends CardTestPlayerBaseWithAIHelps {
System.out.println(horizontalBorder); System.out.println(horizontalBorder);
} }
prevGroup = dialog.getGroup(); prevGroup = dialog.getGroup();
String status = dialog.getResult().isOk() ? "OK" : "FAIL"; String status;
if (dialog.getResult().getResAssert() == null) {
status = asYellow("?");
totalUnknown++;
} else if (dialog.getResult().getResAssert()) {
totalGood++;
status = asGreen("OK");
} else {
totalBad++;
status = asRed("FAIL");
}
System.out.printf(rowFormat, dialog.getGroup(), dialog.getName(), status); System.out.printf(rowFormat, dialog.getGroup(), dialog.getName(), status);
} }
System.out.println(horizontalBorder); System.out.println(horizontalBorder);
@ -160,7 +175,28 @@ public class TestableDialogsTest extends CardTestPlayerBaseWithAIHelps {
System.out.printf("| %-" + (maxGroupLength + maxNameLength + maxResultLength + 6) + "s |%n", System.out.printf("| %-" + (maxGroupLength + maxNameLength + maxResultLength + 6) + "s |%n",
"Total dialogs: " + totalDialogs); "Total dialogs: " + totalDialogs);
System.out.printf("| %-" + (maxGroupLength + maxNameLength + maxResultLength + 6) + "s |%n", System.out.printf("| %-" + (maxGroupLength + maxNameLength + maxResultLength + 6) + "s |%n",
"Total results: TODO"); String.format("Total results: %s good, %s bad, %s unknown",
asGreen(String.valueOf(totalGood)),
asRed(String.valueOf(totalBad)),
asYellow(String.valueOf(totalUnknown))
)
);
System.out.println(horizontalBorder); System.out.println(horizontalBorder);
if (assertGoodResults && totalBad > 0) {
Assert.fail(String.format("Testable dialogs has %d bad results, try to fix it", totalBad));
}
}
private String asRed(String text) {
return "\u001B[31m" + text + "\u001B[0m";
}
private String asGreen(String text) {
return "\u001B[32m" + text + "\u001B[0m";
}
private String asYellow(String text) {
return "\u001B[33m" + text + "\u001B[0m";
} }
} }