Cheats: improved cheat and test commands to use same set_code-card_name notation, added additional tests (related to #10139, cheat command example: battlefield:Human:XLN-Island:1)

This commit is contained in:
Oleg Agafonov 2023-04-04 22:05:22 +04:00
parent 00b6113244
commit a6337fd28a
6 changed files with 84 additions and 28 deletions

View file

@ -87,7 +87,10 @@ public final class SystemUtil {
private static final Pattern patternGroup = Pattern.compile("\\[(.+)\\]"); // [test new card] private static final Pattern patternGroup = Pattern.compile("\\[(.+)\\]"); // [test new card]
private static final Pattern patternCommand = Pattern.compile("([\\w]+):([\\S ]+?):([\\S ]+):([\\d]+)"); // battlefield:Human:Island:10 private static final Pattern patternCommand = Pattern.compile("([\\w]+):([\\S ]+?):([\\S ]+):([\\d]+)"); // battlefield:Human:Island:10
private static final Pattern patternCardInfo = Pattern.compile("([\\S ]+):([\\S ]+)"); // Island:XLN private static final Pattern patternCardInfo = Pattern.compile("(^[\\dA-Z]{2,7})@([\\S ]+)" // XLN-Island
.replace("7", String.valueOf(CardUtil.TESTS_SET_CODE_LOOKUP_LENGTH))
.replace("@", CardUtil.TESTS_SET_CODE_DELIMETER)
);
// show ext info for special commands // show ext info for special commands
private static final String PARAM_COLOR_COST = "color cost"; private static final String PARAM_COLOR_COST = "color cost";
@ -220,17 +223,10 @@ public final class SystemUtil {
} }
// card name can be with set // card name can be with set
String cardInfo = matchCommand.group(3); // example: XLN-Island
Matcher matchInfo = patternCardInfo.matcher(cardInfo); List<String> cardInfo = parseSetAndCardNameCommand(matchCommand.group(3));
if (matchInfo.matches()) { com.cardSet = cardInfo.get(0);
// name with set com.cardName = cardInfo.get(1);
com.cardName = matchInfo.group(1);
com.cardSet = matchInfo.group(2);
} else {
// name only
com.cardName = cardInfo;
com.cardSet = "";
}
if (com.cardName.isEmpty()) { if (com.cardName.isEmpty()) {
com.Error = "Card name is empty"; com.Error = "Card name is empty";
@ -729,4 +725,22 @@ public final class SystemUtil {
long diffInMillies = date2.getTime() - date1.getTime(); long diffInMillies = date2.getTime() - date1.getTime();
return timeUnit.convert(diffInMillies, TimeUnit.MILLISECONDS); return timeUnit.convert(diffInMillies, TimeUnit.MILLISECONDS);
} }
/**
* Parse set code and card name from command line
*
* @param info format example: XLN-Mountain (set code must be upper case)
* @return
*/
public static List<String> parseSetAndCardNameCommand(String info) {
Matcher matchInfo = patternCardInfo.matcher(info);
String cardSet = "";
String cardName = info;
if (matchInfo.matches()) {
// set with card
cardSet = matchInfo.group(1);
cardName = matchInfo.group(2);
}
return Arrays.asList(cardSet, cardName);
}
} }

View file

@ -15,7 +15,7 @@ public class TokenImagesTest extends CardTestPlayerBase {
@Test @Test
public void test_TokenMustGetSameSetCodeAsSourceCard() { public void test_TokenMustGetSameSetCodeAsSourceCard() {
//{3}{W}, {T}, Sacrifice Memorial to Glory: Create two 1/1 white Soldier creature tokens. //{3}{W}, {T}, Sacrifice Memorial to Glory: Create two 1/1 white Soldier creature tokens.
addCard(Zone.BATTLEFIELD, playerA, "40K:Memorial to Glory"); addCard(Zone.BATTLEFIELD, playerA, "40K-Memorial to Glory");
addCard(Zone.BATTLEFIELD, playerA, "Plains", 4); addCard(Zone.BATTLEFIELD, playerA, "Plains", 4);
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{3}{W}, {T}, Sacrifice"); activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{3}{W}, {T}, Sacrifice");

View file

@ -600,7 +600,7 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement
* @param gameZone {@link mage.constants.Zone} to add cards to. * @param gameZone {@link mage.constants.Zone} to add cards to.
* @param player {@link Player} to add cards for. Use either playerA or * @param player {@link Player} to add cards for. Use either playerA or
* playerB. * playerB.
* @param cardName Card name or set:card * @param cardName Card name or set-card
* @param count Amount of cards to be added. * @param count Amount of cards to be added.
* @param tapped In case gameZone is Battlefield, determines whether * @param tapped In case gameZone is Battlefield, determines whether
* permanent should be tapped. In case gameZone is other * permanent should be tapped. In case gameZone is other
@ -624,11 +624,9 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement
// set code for card // set code for card
String setCode = ""; String setCode = "";
String setLookup = CardUtil.substring(cardName, CardUtil.TESTS_SET_CODE_LOOKUP_LENGTH); List<String> cardCommand = SystemUtil.parseSetAndCardNameCommand(cardName);
if (setLookup.contains(":")) { setCode = cardCommand.get(0);
setCode = setLookup.substring(0, setLookup.indexOf(":")); cardName = cardCommand.get(1);
cardName = cardName.substring(setCode.length() + 1);
}
CardInfo cardInfo; CardInfo cardInfo;
if (setCode.isEmpty()) { if (setCode.isEmpty()) {

View file

@ -2,15 +2,55 @@ package org.mage.test.testapi;
import mage.constants.PhaseStep; import mage.constants.PhaseStep;
import mage.constants.Zone; import mage.constants.Zone;
import mage.server.util.SystemUtil;
import org.junit.Assert; import org.junit.Assert;
import org.junit.Test; import org.junit.Test;
import org.mage.test.serverside.base.CardTestPlayerBase; import org.mage.test.serverside.base.CardTestPlayerBase;
import java.util.List;
/** /**
* @author JayDi85 * @author JayDi85
*/ */
public class AddCardApiTest extends CardTestPlayerBase { public class AddCardApiTest extends CardTestPlayerBase {
@Test
public void test_CardParsing() {
List<String> info;
info = SystemUtil.parseSetAndCardNameCommand("");
Assert.assertEquals(2, info.size());
Assert.assertEquals("", info.get(0));
Assert.assertEquals("", info.get(1));
info = SystemUtil.parseSetAndCardNameCommand("single name");
Assert.assertEquals(2, info.size());
Assert.assertEquals("", info.get(0));
Assert.assertEquals("single name", info.get(1));
info = SystemUtil.parseSetAndCardNameCommand("SET-name");
Assert.assertEquals(2, info.size());
Assert.assertEquals("SET", info.get(0));
Assert.assertEquals("name", info.get(1));
// only upper case set codes can be used
info = SystemUtil.parseSetAndCardNameCommand("non-set-code-name");
Assert.assertEquals(2, info.size());
Assert.assertEquals("", info.get(0));
Assert.assertEquals("non-set-code-name", info.get(1));
info = SystemUtil.parseSetAndCardNameCommand("SET-card-name");
Assert.assertEquals(2, info.size());
Assert.assertEquals("SET", info.get(0));
Assert.assertEquals("card-name", info.get(1));
// must find first symbols before delimeter, e.g. TOO
info = SystemUtil.parseSetAndCardNameCommand("TOO-LONG-SET-card-name");
Assert.assertEquals(2, info.size());
Assert.assertEquals("TOO", info.get(0));
Assert.assertEquals("LONG-SET-card-name", info.get(1));
}
@Test @Test
public void test_CardName_Normal() { public void test_CardName_Normal() {
addCard(Zone.BATTLEFIELD, playerA, "Plains", 3); addCard(Zone.BATTLEFIELD, playerA, "Plains", 3);
@ -30,8 +70,8 @@ public class AddCardApiTest extends CardTestPlayerBase {
@Test @Test
public void test_CardNameWithSetCode_Normal() { public void test_CardNameWithSetCode_Normal() {
addCard(Zone.BATTLEFIELD, playerA, "40K:Memorial to Glory", 2); addCard(Zone.BATTLEFIELD, playerA, "40K-Memorial to Glory", 2);
addCard(Zone.BATTLEFIELD, playerA, "PANA:Plains", 2); addCard(Zone.BATTLEFIELD, playerA, "PANA-Plains", 2);
setStrictChooseMode(true); setStrictChooseMode(true);
setStopAt(1, PhaseStep.BEGIN_COMBAT); setStopAt(1, PhaseStep.BEGIN_COMBAT);
@ -50,6 +90,6 @@ public class AddCardApiTest extends CardTestPlayerBase {
@Test(expected = org.junit.ComparisonFailure.class) @Test(expected = org.junit.ComparisonFailure.class)
public void test_CardNameWithSetCode_RaiseErrorOnUnknownSet() { public void test_CardNameWithSetCode_RaiseErrorOnUnknownSet() {
addCard(Zone.BATTLEFIELD, playerA, "SS4:Plains", 1); addCard(Zone.BATTLEFIELD, playerA, "SS4-Plains", 1);
} }
} }

View file

@ -29,6 +29,7 @@ import mage.game.draft.DraftCube;
import mage.game.draft.RateCard; import mage.game.draft.RateCard;
import mage.game.permanent.token.Token; import mage.game.permanent.token.Token;
import mage.game.permanent.token.TokenImpl; import mage.game.permanent.token.TokenImpl;
import mage.server.util.SystemUtil;
import mage.sets.TherosBeyondDeath; import mage.sets.TherosBeyondDeath;
import mage.util.CardUtil; import mage.util.CardUtil;
import mage.verify.mtgjson.MtgJsonCard; import mage.verify.mtgjson.MtgJsonCard;
@ -964,7 +965,7 @@ public class VerifyCardDataTest {
cardNames.add(cardInfo.getName()); cardNames.add(cardInfo.getName());
} }
// CHECK: set code must be compatible with tests commands format // CHECK: set code must be compatible with tests commands format like "SET-card"
// how-to fix: increase lookup lenth // how-to fix: increase lookup lenth
if (set.getCode().length() + 1 > CardUtil.TESTS_SET_CODE_LOOKUP_LENGTH) { if (set.getCode().length() + 1 > CardUtil.TESTS_SET_CODE_LOOKUP_LENGTH) {
errorsList.add("Error: set code too big for test commads lookup: " + set.getCode() + ", lookup length: " + CardUtil.TESTS_SET_CODE_LOOKUP_LENGTH); errorsList.add("Error: set code too big for test commads lookup: " + set.getCode() + ", lookup length: " + CardUtil.TESTS_SET_CODE_LOOKUP_LENGTH);
@ -995,10 +996,12 @@ public class VerifyCardDataTest {
errorsList.add("Error: card name or number contains non-ascii symbols: " + set.getCode() + " - " + set.getName() + " - " + card.getName() + " - " + card.getCardNumber()); errorsList.add("Error: card name or number contains non-ascii symbols: " + set.getCode() + " - " + set.getName() + " - " + card.getName() + " - " + card.getCardNumber());
} }
// CHECK: card name must not contain : symbol due set:name commands format in test engine // CHECK: set code and card name must be parseable for test and cheat commands XLN-Mountain
// (if it exists then decrease TESTS_SET_CODE_LOOKUP_LENGTH) List<String> cardCommand = SystemUtil.parseSetAndCardNameCommand(set.getCode() + CardUtil.TESTS_SET_CODE_DELIMETER + card.getName());
if (CardUtil.substring(card.getName(), CardUtil.TESTS_SET_CODE_LOOKUP_LENGTH).contains(":")) { if (!Objects.equals(set.getCode(), cardCommand.get(0))
errorsList.add("Error: card name can't contain : symbol: " + set.getCode() + " - " + set.getName() + " - " + card.getName() + " - " + card.getCardNumber()); || !Objects.equals(card.getName(), cardCommand.get(1))) {
// if you catch it then parser logic must be changed to support problem set-card combination
errorsList.add("Error: card name can't be used in tests and cheats with set code: " + set.getCode() + " - " + set.getName() + " - " + card.getName() + " - " + card.getCardNumber());
} }
// CHECK: card number must start with 09-aZ symbols (wrong symbol example: *123) // CHECK: card number must start with 09-aZ symbols (wrong symbol example: *123)

View file

@ -77,7 +77,8 @@ public final class CardUtil {
"put", "return", "exile", "discard", "sacrifice", "remove", "tap", "reveal", "pay" "put", "return", "exile", "discard", "sacrifice", "remove", "tap", "reveal", "pay"
); );
public static final int TESTS_SET_CODE_LOOKUP_LENGTH = 10; // search set code in commands like "set:card_name" public static final int TESTS_SET_CODE_LOOKUP_LENGTH = 6; // search set code in commands like "set_code-card_name"
public static final String TESTS_SET_CODE_DELIMETER = "-"; // delimeter for cheats and tests command "set_code-card_name"
/** /**
* Increase spell or ability cost to be paid. * Increase spell or ability cost to be paid.