/* * SkillTokenTest.java * Copyright 2004 (C) James Dempsey <jdempsey@users.sourceforge.net> * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Created on Aug 7, 2004 * * $Id$ * */ package pcgen.io; import java.io.BufferedWriter; import java.io.File; import java.io.FileWriter; import java.io.IOException; import java.io.StringWriter; import java.util.ArrayList; import java.util.List; import junit.framework.Test; import junit.framework.TestSuite; import pcgen.AbstractCharacterTestCase; import pcgen.cdom.base.FormulaFactory; import pcgen.cdom.enumeration.FormulaKey; import pcgen.cdom.enumeration.ListKey; import pcgen.cdom.enumeration.ObjectKey; import pcgen.cdom.enumeration.Type; import pcgen.cdom.enumeration.VariableKey; import pcgen.cdom.reference.CDOMDirectSingleRef; import pcgen.core.Ability; import pcgen.core.AbilityCategory; import pcgen.core.Equipment; import pcgen.core.GameMode; import pcgen.core.Globals; import pcgen.core.LevelInfo; import pcgen.core.PCClass; import pcgen.core.PCStat; import pcgen.core.PlayerCharacter; import pcgen.core.Race; import pcgen.core.SettingsHandler; import pcgen.core.Skill; import pcgen.core.analysis.SkillRankControl; import pcgen.core.bonus.Bonus; import pcgen.core.bonus.BonusObj; import pcgen.core.character.EquipSet; import pcgen.rules.context.LoadContext; import pcgen.util.TestHelper; /** * <code>SkillTokenTest</code> contains tests to verify that the * SKILL token and its subtokens are working correctly. * * * @author James Dempsey <jdempsey@users.sourceforge.net> */ @SuppressWarnings("nls") public class ExportHandlerTest extends AbstractCharacterTestCase { private Skill balance = null; private Skill[] knowledge = null; private Skill tumble = null; private Equipment weapon = null; private Equipment gem = null; private Equipment armor = null; /** * Quick test suite creation - adds all methods beginning with "test" * @return The Test suite */ public static Test suite() { return new TestSuite(ExportHandlerTest.class); } /** * Basic constructor, name only. * @param name The name of the test class. */ public ExportHandlerTest(String name) { super(name); } /** * @see pcgen.AbstractCharacterTestCase#setUp() */ @Override protected void setUp() throws Exception { super.setUp(); PlayerCharacter character = getCharacter(); LoadContext context = Globals.getContext(); final LevelInfo levelInfo = new LevelInfo(); levelInfo.setLevelString("LEVEL"); levelInfo.setMaxClassSkillString("LEVEL+3"); levelInfo.setMaxCrossClassSkillString("(LEVEL+3)/2"); GameMode gamemode = SettingsHandler.getGame(); gamemode.addLevelInfo("Default", levelInfo); //Stats setPCStat(character, dex, 16); setPCStat(character, intel, 17); BonusObj aBonus = Bonus.newBonus(context, "MODSKILLPOINTS|NUMBER|INT"); if (aBonus != null) { intel.addToListFor(ListKey.BONUS, aBonus); } // Race Race testRace = new Race(); testRace.setName("TestRace"); character.setRace(testRace); // Class PCClass myClass = new PCClass(); myClass.setName("My Class"); myClass.put(FormulaKey.START_SKILL_POINTS, FormulaFactory.getFormulaFor(3)); character.incrementClassLevel(5, myClass, true); // Skills knowledge = new Skill[2]; knowledge[0] = new Skill(); context.unconditionallyProcess(knowledge[0], "CLASSES", "MyClass"); knowledge[0].setName("KNOWLEDGE (ARCANA)"); TestHelper.addType(knowledge[0], "KNOWLEDGE.INT"); CDOMDirectSingleRef<PCStat> intelRef = CDOMDirectSingleRef.getRef(intel); knowledge[0].put(ObjectKey.KEY_STAT, intelRef); character.setSkillOrder(knowledge[0], 2); Globals.getContext().getReferenceContext().importObject(knowledge[0]); SkillRankControl.modRanks(8.0, myClass, true, character, knowledge[0]); knowledge[1] = new Skill(); context.unconditionallyProcess(knowledge[1], "CLASSES", "MyClass"); knowledge[1].setName("KNOWLEDGE (RELIGION)"); TestHelper.addType(knowledge[1], "KNOWLEDGE.INT"); knowledge[1].put(ObjectKey.KEY_STAT, intelRef); character.setSkillOrder(knowledge[1], 3); Globals.getContext().getReferenceContext().importObject(knowledge[1]); SkillRankControl.modRanks(5.0, myClass, true, character, knowledge[1]); tumble = new Skill(); context.unconditionallyProcess(tumble, "CLASSES", "MyClass"); tumble.setName("Tumble"); tumble.addToListFor(ListKey.TYPE, Type.getConstant("DEX")); CDOMDirectSingleRef<PCStat> dexRef = CDOMDirectSingleRef.getRef(dex); tumble.put(ObjectKey.KEY_STAT, dexRef); character.setSkillOrder(tumble, 4); Globals.getContext().getReferenceContext().importObject(tumble); SkillRankControl.modRanks(7.0, myClass, true, character, tumble); balance = new Skill(); context.unconditionallyProcess(balance, "CLASSES", "MyClass"); balance.setName("Balance"); balance.addToListFor(ListKey.TYPE, Type.getConstant("DEX")); balance.put(ObjectKey.KEY_STAT, dexRef); character.setSkillOrder(balance, 1); aBonus = Bonus.newBonus(context, "SKILL|Balance|2|PRESKILL:1,Tumble=5|TYPE=Synergy.STACK"); if (aBonus != null) { balance.addToListFor(ListKey.BONUS, aBonus); } Globals.getContext().getReferenceContext().importObject(balance); SkillRankControl.modRanks(4.0, myClass, true, character, balance); character.calcActiveBonuses(); weapon = new Equipment(); weapon.setName("TestWpn"); weapon.addToListFor(ListKey.TYPE, Type.WEAPON); gem = new Equipment(); gem.setName("TestGem"); gem.addToListFor(ListKey.TYPE, Type.getConstant("gem")); gem.setQty(1); armor = new Equipment(); armor.setName("TestArmorSuit"); TestHelper.addType(armor, "armor.suit"); context.getReferenceContext().buildDerivedObjects(); context.getReferenceContext().resolveReferences(null); } /** * @see pcgen.AbstractCharacterTestCase#tearDown() */ @Override protected void tearDown() throws Exception { knowledge = null; balance = null; tumble = null; intel.removeListFor(ListKey.BONUS); super.tearDown(); } /** * Test the behaviour of the weapon loop * @throws IOException */ public void testWpnLoop() throws IOException { PlayerCharacter character = getCharacter(); // Test each token for old and new syntax processing. assertEquals("New format SKILL Token", "****", evaluateToken( "FOR.0,100,1,**\\WEAPON.%.NAME\\**,NONE,NONE,1", character)); // Now assign a weapon character.addEquipment(weapon); EquipSet es = new EquipSet("1", "Default", "", weapon); character.addEquipSet(es); assertEquals("New format SKILL Token", "**TestWpn**", evaluateToken( "FOR.0,100,1,**\\WEAPON.%.NAME\\**,NONE,NONE,1", character)); } /** * Test the export of equipment using the eqtype token in a loop. * * @throws Exception */ public void testEqtypeLoop() throws Exception { PlayerCharacter character = getCharacter(); final String gemLoop = "FOR.0,COUNT[EQTYPE.Gem],1,\\EQTYPE.Gem.%.NAME\\: \\EQTYPE.Gem.%.QTY\\, ,<br/>,1"; assertEquals("Gem Loop - no gems", "", evaluateToken(gemLoop, character)); // Now assign a gem character.addEquipment(gem); EquipSet es = new EquipSet("1", "Default", "", gem); character.addEquipSet(es); character.setDirty(true); assertEquals("Gem loop - 1 gem", " TestGem: 1<br/>", evaluateToken( gemLoop, character)); } public void testJepIif() throws IOException { PlayerCharacter character = getCharacter(); assertEquals("Basic JEP boolean", new Float(1.0), character .getVariableValue("max(0,2)==2", "")); assertEquals("JEP boolean in IF", "true", evaluateToken( "OIF(max(0,2)==2,true,false)", character)); // assertEquals("JEP boolean in IF", "true", evaluateToken( // "|OIF(max(0,2)==2)|\ntrue\n|ELSE|\nfalse\n|ENDIF|", character)); } public void testFor() throws IOException { PlayerCharacter pc = getCharacter(); Ability dummyFeat1 = new Ability(); dummyFeat1.setName("1"); dummyFeat1.setCDOMCategory(AbilityCategory.FEAT); Ability dummyFeat2 = new Ability(); dummyFeat2.setName("2"); dummyFeat2.setCDOMCategory(AbilityCategory.FEAT); Ability dummyFeat3 = new Ability(); dummyFeat3.setName("3"); dummyFeat3.setCDOMCategory(AbilityCategory.FEAT); Ability dummyFeat4 = new Ability(); dummyFeat4.setName("4"); dummyFeat4.setCDOMCategory(AbilityCategory.FEAT); Ability dummyFeat5 = new Ability(); dummyFeat5.setName("5"); dummyFeat5.setCDOMCategory(AbilityCategory.FEAT); Ability dummyFeat6 = new Ability(); dummyFeat6.setName("6"); dummyFeat6.setCDOMCategory(AbilityCategory.FEAT); Ability dummyFeat7 = new Ability(); dummyFeat7.setName("7"); dummyFeat7.setCDOMCategory(AbilityCategory.FEAT); addAbility(AbilityCategory.FEAT, dummyFeat1); addAbility(AbilityCategory.FEAT, dummyFeat2); addAbility(AbilityCategory.FEAT, dummyFeat3); addAbility(AbilityCategory.FEAT, dummyFeat4); addAbility(AbilityCategory.FEAT, dummyFeat5); addAbility(AbilityCategory.FEAT, dummyFeat6); addAbility(AbilityCategory.FEAT, dummyFeat7); assertEquals("Test for evaluates correctly", "----------------", evaluateToken( "FOR.1,((24-STRLEN[SKILL.0])),24,-,NONE,NONE,1", pc)); assertEquals("Test for evaluates correctly", " ", evaluateToken( "FOR.1,((24-STRLEN[SKILL.0])),24, ,NONE,NONE,1", pc)); String tok = "DFOR." + "0" + ",${((count(\"ABILITIES\";\"CATEGORY=FEAT\")+1)/2)}" + ",1" + ",${(count(\"ABILITIES\";\"CATEGORY=FEAT\")+1)}" + ",${((count(\"ABILITIES\";\"CATEGORY=FEAT\")+1)/2)}" + ", \\FEAT.%.NAME\\ " + ",[" + ",]" + ",0"; //Logging.errorPrint( "DFOR Test: " + evaluateToken(tok, pc)); // Test DFOR with alternate syntax for jep passthrough. ie, anything // surrounded by ${x} will tbe sent straight to be processed. We // will assume that x is a well formed type of value. This was to get around // the problems with DFOR not taking ((count("ABILITIES";"CATEGORY=FEAT")+1) // since it could not figure out how to parse it to send to the right place. assertEquals("Test for DFOR ","[ 1 5 ][ 2 6 ][ 3 7 ][ 4 ]", evaluateToken(tok, pc) ); } public void testForNoMoreItems() throws IOException { PlayerCharacter pc = getCharacter(); assertEquals("Test for evaluates correctly", "SF", evaluateToken( "FOR.0,100,1,\\ARMOR.SUIT.ALL.%.NAME\\,S,F,1", pc)); // Now assign a gem pc.addEquipment(armor); EquipSet es = new EquipSet("1", "Default", "", armor); pc.addEquipSet(es); assertEquals("Test for evaluates correctly", "STestArmorSuitFSF", evaluateToken( "FOR.0,100,1,\\ARMOR.SUIT.ALL.%.NAME\\,S,F,1", pc)); } public void testExpressionOutput() throws IOException { LoadContext context = Globals.getContext(); Ability dummyFeat = new Ability(); dummyFeat.setName("DummyFeat"); dummyFeat.setCDOMCategory(AbilityCategory.FEAT); final PlayerCharacter pc = getCharacter(); // Create a variable dummyFeat.put(VariableKey.getConstant("NegLevels"), FormulaFactory .getFormulaFor(0)); // Create a bonus to it Ability dummyFeat2 = new Ability(); dummyFeat2.setName("DummyFeat2"); dummyFeat2.setCDOMCategory(AbilityCategory.FEAT); final BonusObj aBonus = Bonus.newBonus(context, "VAR|NegLevels|7"); if (aBonus != null) { dummyFeat2.addToListFor(ListKey.BONUS, aBonus); } AbilityCategory cat = context.getReferenceContext().constructCDOMObject( AbilityCategory.class, "Maneuver"); AbilityCategory cat2 = context.getReferenceContext().constructCDOMObject( AbilityCategory.class, "Maneuver(Special)"); Ability dummyFeat3 = new Ability(); dummyFeat3.setName("DummyFeat3"); dummyFeat3.setCDOMCategory(cat); Ability dummyFeat4 = new Ability(); dummyFeat4.setName("DummyFeat4"); dummyFeat4.setCDOMCategory(cat2); addAbility(AbilityCategory.FEAT, dummyFeat); addAbility(AbilityCategory.FEAT, dummyFeat2); addAbility(cat, dummyFeat3); addAbility(cat2, dummyFeat4); assertEquals("Unsigned output", "7", evaluateToken( "VAR.NegLevels.INTVAL", pc)); assertEquals("Signed output", "+7", evaluateToken( "VAR.NegLevels.INTVAL.SIGN", pc)); String tok =""; tok = "count(\"ABILITIES\", \"CATEGORY=Maneuver\")"; // if this evaluates math wise, the values should be string "1.0" assertFalse("Token: |" + tok + "| != 1.0: ", evaluateToken(tok, pc).equals("1.0")); tok = "VAR.count(\"ABILITIES\", \"CATEGORY=Maneuver\")"; assertTrue("Token: |" + tok + "| == 1.0: ", evaluateToken(tok, pc).equals("1.0")); tok ="COUNT[\"ABILITIES\", \"CATEGORY=Maneuver\"]"; assertFalse("Token: |" + tok + "| != 1.0: ", evaluateToken(tok, pc).equals("1.0")); tok = "count(\"ABILITIES\", \"CATEGORY=Maneuver(Special)\")"; assertFalse("Token: |" + tok + "| != 1.0 ", evaluateToken(tok, pc).equals("1.0")); tok = "${count(\"ABILITIES\", \"CATEGORY=Maneuver(Special)\")+5}"; assertFalse("Token: |" + tok + "| == 5.0 ", evaluateToken(tok, pc).equals("5.0")); tok = "${count(\"ABILITIES\", \"CATEGORY=Maneuver(Special)\")+5}"; assertTrue("Token: |" + tok + "| != 6.0 ", evaluateToken(tok, pc).equals("6.0")); tok = "${(count(\"ABILITIES\", \"CATEGORY=Maneuver(Special)\")+5)/3}"; assertFalse("Token: |" + tok + "| == 3.0 ", evaluateToken(tok, pc).equals("3.0")); tok = "${(count(\"ABILITIES\", \"CATEGORY=Maneuver(Special)\")+5)/3}"; assertTrue("Token: |" + tok + "| != 2.0 ", evaluateToken(tok, pc).equals("2.0")); } public void testPartyFor() throws IOException { String outputToken = " <combatants>\n" + "|FOR.0,50,1,\n" + " <name>\\\\%.NAME\\\\</name>\n" + " <skills>\\\\%.FOR.0,COUNT[SKILLS],1,\\SKILL.%\\: \\SKILL.%.TOTAL.SIGN\\, ,; ,1\\\\</skills>\n" + ",<combatant>,</combatant>,1|\n" + " </combatants>"; List<PlayerCharacter> pcs = new ArrayList<>(); pcs.add(getCharacter()); String result = evaluatePartyToken(outputToken, pcs).trim(); assertEquals( "Party skills output", "<combatants>" + System.getProperty("line.separator") + "<combatant> <name></name> <skills> Balance: +9; KNOWLEDGE (ARCANA): +11; KNOWLEDGE (RELIGION): +8; Tumble: +10; </skills></combatant> </combatants>", result); } private String evaluateToken(String token, PlayerCharacter pc) throws IOException { StringWriter retWriter = new StringWriter(); BufferedWriter bufWriter = new BufferedWriter(retWriter); ExportHandler export = new ExportHandler(new File("")); export.replaceToken(token, bufWriter, pc); retWriter.flush(); bufWriter.flush(); return retWriter.toString(); } private String evaluatePartyToken(String token, List<PlayerCharacter> pcs) throws IOException { // Create temp file. File temp = File.createTempFile("testTemplate", ".txt"); // Delete temp file when program exits. temp.deleteOnExit(); // Write to temp file BufferedWriter out = new BufferedWriter(new FileWriter(temp)); out.write(token); out.close(); StringWriter retWriter = new StringWriter(); BufferedWriter bufWriter = new BufferedWriter(retWriter); ExportHandler export = new ExportHandler(temp); export.write(pcs, bufWriter); retWriter.flush(); bufWriter.flush(); return retWriter.toString(); } }