mirror of https://github.com/FreeCol/freecol.git
761 lines
25 KiB
Java
761 lines
25 KiB
Java
/**
|
|
* Copyright (C) 2002-2022 The FreeCol Team
|
|
*
|
|
* This file is part of FreeCol.
|
|
*
|
|
* FreeCol is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation, either version 2 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* FreeCol 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 General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with FreeCol. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
package net.sf.freecol.util.test;
|
|
|
|
import java.lang.reflect.Field;
|
|
|
|
import java.util.ArrayList;
|
|
import java.util.HashMap;
|
|
import java.util.List;
|
|
import java.util.Locale;
|
|
|
|
import junit.framework.TestCase;
|
|
import net.sf.freecol.FreeCol;
|
|
import net.sf.freecol.common.i18n.Messages;
|
|
import net.sf.freecol.common.io.FreeColTcFile;
|
|
import net.sf.freecol.common.model.AbstractGoods;
|
|
import net.sf.freecol.common.model.Colony;
|
|
import net.sf.freecol.common.model.CombatModel;
|
|
import net.sf.freecol.common.model.CombatModel.CombatOdds;
|
|
import net.sf.freecol.common.model.CombatModel.CombatResult;
|
|
import net.sf.freecol.common.model.FreeColGameObject;
|
|
import net.sf.freecol.common.model.Game;
|
|
import net.sf.freecol.common.model.IndianSettlement;
|
|
import net.sf.freecol.common.model.Map;
|
|
import net.sf.freecol.common.model.Nation;
|
|
import net.sf.freecol.common.model.NationOptions;
|
|
import net.sf.freecol.common.model.Player;
|
|
import net.sf.freecol.common.model.Region;
|
|
import net.sf.freecol.common.model.Specification;
|
|
import net.sf.freecol.common.model.Tile;
|
|
import net.sf.freecol.common.model.TileType;
|
|
import net.sf.freecol.common.model.Unit;
|
|
import net.sf.freecol.common.model.UnitChangeType;
|
|
import net.sf.freecol.common.model.UnitType;
|
|
import net.sf.freecol.common.model.UnitTypeChange;
|
|
import net.sf.freecol.common.model.WorkLocation;
|
|
import static net.sf.freecol.common.util.CollectionUtils.*;
|
|
import net.sf.freecol.server.model.ServerGame;
|
|
import net.sf.freecol.server.model.ServerIndianSettlement;
|
|
import net.sf.freecol.server.model.ServerPlayer;
|
|
import net.sf.freecol.server.model.ServerUnit;
|
|
|
|
|
|
/**
|
|
* The base class for all FreeCol tests. Contains useful methods used by the
|
|
* individual tests.
|
|
*/
|
|
public class FreeColTestCase extends TestCase {
|
|
|
|
/** We now have lots of maps, restrict testing to just the old ones. */
|
|
public static String[] STANDARD_MAPS = {
|
|
"data/maps/M_Africa_Gilolat.fsm",
|
|
"data/maps/S_AustraliaOceania_Gilolat.fsm",
|
|
"data/maps/L_America_JsTheDude.fsm",
|
|
"data/maps/S_Caribbean_Phil.fsm"
|
|
};
|
|
|
|
private static java.util.Map<String, Specification> specifications
|
|
= new HashMap<>();
|
|
|
|
/**
|
|
* use getGame to access this.
|
|
*/
|
|
static Game game;
|
|
|
|
static boolean updateLocale = true;
|
|
|
|
@Override
|
|
protected void setUp() throws Exception {
|
|
FreeColTcFile.loadTCs();
|
|
if (updateLocale) {
|
|
updateLocale = false;
|
|
Messages.loadMessageBundle(Locale.US);
|
|
}
|
|
}
|
|
|
|
@Override
|
|
protected void tearDown() throws Exception {
|
|
// If a game has been created destroy it.
|
|
game = null;
|
|
}
|
|
|
|
/**
|
|
* Get a game pseudo-singleton, i.e. the same instance will be returned
|
|
* until getStandardGame() is called, which resets the singleton to a new
|
|
* value.
|
|
*
|
|
* Calling this method repetitively without calling getStandardGame() will
|
|
* result in the same Game being returned.
|
|
*
|
|
* @return The game singleton.
|
|
*/
|
|
public static Game getGame() {
|
|
if (game == null) {
|
|
game = getStandardGame();
|
|
}
|
|
return game;
|
|
}
|
|
|
|
/**
|
|
* Specifically sets the game instance to run with. Necessary for
|
|
* server tests that create their own game instances. Allows for
|
|
* same interface for accessing the game instance for all types of
|
|
* tests.
|
|
*
|
|
* @param newGame Game instance to work with
|
|
*/
|
|
public static void setGame(Game newGame) {
|
|
game = newGame;
|
|
}
|
|
|
|
public static Specification spec() {
|
|
return getSpecification("freecol");
|
|
}
|
|
|
|
public static Specification spec(String name) {
|
|
return getSpecification(name);
|
|
}
|
|
|
|
public static Specification getSpecification(String name) {
|
|
Specification result = specifications.get(name);
|
|
if (result == null) {
|
|
FreeColTcFile.loadTCs();
|
|
try {
|
|
FreeColTcFile tc = FreeColTcFile.getFreeColTcFile(name);
|
|
result = FreeCol.loadSpecification(tc, null, "model.difficulty.medium");
|
|
specifications.put(name, result);
|
|
} catch (Exception e) {
|
|
e.printStackTrace();
|
|
return null;
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Returns a new game, with all players set.
|
|
*
|
|
* As a side effect this call will reset the singleton game value that can
|
|
* be accessed using getGame().
|
|
*
|
|
* @return A new game with with players for each nation added.
|
|
*/
|
|
public static Game getStandardGame() {
|
|
return getStandardGame("freecol");
|
|
}
|
|
|
|
/**
|
|
* Returns a new game, with all players set.
|
|
*
|
|
* As a side effect this call will reset the singleton game value that can
|
|
* be accessed using getGame().
|
|
*
|
|
* @param specName a {@code String} value
|
|
* @return A new game with with players for each nation added.
|
|
*/
|
|
public static Game getStandardGame(String specName) {
|
|
Specification specification = spec(specName);
|
|
game = new ServerGame(specification);
|
|
NationOptions nationOptions = new NationOptions(specification);
|
|
for (Nation nation : specification.getEuropeanNations()) {
|
|
nationOptions.setNationState(nation, NationOptions.NationState.AVAILABLE);
|
|
}
|
|
game.setNationOptions(nationOptions);
|
|
|
|
specification.applyDifficultyLevel("model.difficulty.medium");
|
|
for (Nation n : specification.getNations()) {
|
|
if (n.isUnknownEnemy()) continue;
|
|
Player p = new ServerPlayer(game, false, n);
|
|
boolean ai = !n.getType().isEuropean() || n.getType().isREF();
|
|
p.setAI(ai);
|
|
if (ai || game.canAddNewPlayer()) game.addPlayer(p);
|
|
}
|
|
return game;
|
|
}
|
|
|
|
/**
|
|
* Creates a standardized map on which all fields have the plains type.
|
|
*
|
|
* Uses the getGame() method to access the currently running game.
|
|
*
|
|
* Does not call Game.setMap(Map) with the returned map. The map
|
|
* is unexplored.
|
|
*
|
|
* @return The map created as described above.
|
|
*/
|
|
public static Map getTestMap() {
|
|
MapBuilder builder = new MapBuilder(getGame());
|
|
return builder.build();
|
|
}
|
|
|
|
/**
|
|
* Creates a standardized map on which all fields have the same given type.
|
|
*
|
|
* Uses the getGame() method to access the currently running game.
|
|
*
|
|
* Does not call Game.setMap(Map) with the returned map. The map
|
|
* is unexplored.
|
|
*
|
|
* @param tileType The type of land with which to initialize the map.
|
|
*
|
|
* @return The map created as described above.
|
|
*/
|
|
public static Map getTestMap(TileType tileType) {
|
|
MapBuilder builder = new MapBuilder(getGame());
|
|
builder.setBaseTileType(tileType);
|
|
return builder.build();
|
|
}
|
|
|
|
/**
|
|
* Creates a standardized map on which all fields have the same given type.
|
|
*
|
|
* Uses the getGame() method to access the currently running game.
|
|
*
|
|
* Does not call Game.setMap(Map) with the returned map.
|
|
*
|
|
* @param tileType The type of land with which to initialize the map.
|
|
* @param explored Set to true if you want all the tiles on the
|
|
* map to have been explored by all players.
|
|
* @return The map created as described above.
|
|
*/
|
|
public static Map getTestMap(TileType tileType, boolean explored) {
|
|
MapBuilder builder = new MapBuilder(getGame());
|
|
builder.setBaseTileType(tileType).setExploredByAll(explored);
|
|
return builder.build();
|
|
}
|
|
|
|
public static Map getTestMap(boolean explored) {
|
|
MapBuilder builder = new MapBuilder(getGame());
|
|
builder.setExploredByAll(explored);
|
|
return builder.build();
|
|
}
|
|
|
|
public static Map getCoastTestMap(TileType landTileType) {
|
|
return getCoastTestMap(landTileType, false);
|
|
}
|
|
|
|
/**
|
|
* Creates a standardized map, half land (left), half sea (right)
|
|
*
|
|
* The land half has the same given type.
|
|
*
|
|
* Uses the getGame() method to access the currently running game.
|
|
*
|
|
* Does not call Game.setMap(Map) with the returned map.
|
|
*
|
|
* @param landTileType The type of land with which to initialize the map.
|
|
*
|
|
* @param explored Set to true if you want all the tiles on the map to have been explored by all players.
|
|
*
|
|
* @return The map created as described above.
|
|
*/
|
|
public static Map getCoastTestMap(TileType landTileType, boolean explored) {
|
|
int totalWidth = 20;
|
|
int totalHeight = 15;
|
|
final TileType oceanType = spec().getTileType("model.tile.ocean");
|
|
|
|
MapBuilder builder = new MapBuilder(getGame());
|
|
builder.setDimensions(totalWidth, totalHeight).setBaseTileType(oceanType);
|
|
if (explored) {
|
|
builder.setExploredByAll(true);
|
|
}
|
|
|
|
// Fill half with land, the builder will fill the rest with ocean
|
|
int landWidth = (int) Math.floor(totalWidth/2);
|
|
for (int x = 0; x < landWidth; x++) {
|
|
for (int y = 0; y < totalHeight; y++) {
|
|
builder.setTileType(x, y, landTileType);
|
|
}
|
|
}
|
|
|
|
// Add high seas.
|
|
final TileType highSeasType = spec().getTileType("model.tile.highSeas");
|
|
for (int y = 0; y < totalHeight; y++) {
|
|
builder.setTileType(totalWidth - 1, y, highSeasType);
|
|
}
|
|
|
|
return builder.build();
|
|
}
|
|
|
|
/**
|
|
* Get a standard colony at the location 5,8 with one free colonist
|
|
*
|
|
* @return The {@code Colony} as specified.
|
|
*/
|
|
public Colony getStandardColony() {
|
|
return getStandardColony(1, 5, 8);
|
|
}
|
|
|
|
/**
|
|
* Get a colony with the given number of settlers
|
|
*
|
|
* @param numberOfSettlers The number of settlers to put into the
|
|
* colony. Must be >= 1.
|
|
* @return The {@code Colony} as specified.
|
|
*/
|
|
public Colony getStandardColony(int numberOfSettlers) {
|
|
return getStandardColony(numberOfSettlers, 5, 8);
|
|
}
|
|
|
|
/**
|
|
* Get a colony with the given number of settlers, at a specified
|
|
* location.
|
|
*
|
|
* @param numberOfSettlers The number of settlers to put into the
|
|
* colony. Must be >= 1.
|
|
* @param tileX Coordinate of tile for the colony.
|
|
* @param tileY Coordinate of tile for the colony.
|
|
* @return The {@code Colony} as specified.
|
|
*/
|
|
public Colony getStandardColony(int numberOfSettlers,
|
|
int tileX, int tileY) {
|
|
Game game = getGame();
|
|
Map map = game.getMap();
|
|
Tile tile = map.getTile(tileX, tileY);
|
|
|
|
FreeColTestUtils.ColonyBuilder builder
|
|
= FreeColTestUtils.getColonyBuilder();
|
|
builder.colonyTile(tile).initialColonists(numberOfSettlers);
|
|
|
|
Colony ret = builder.build();
|
|
((ServerPlayer)ret.getOwner()).exploreForSettlement(ret);
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* Useful utility to make sure a work location is empty before doing
|
|
* some test that implicates it.
|
|
*
|
|
* @param wl The {@code WorkLocation} to clear.
|
|
* @return True if the work location is clear, false if there was a problem
|
|
* removing a unit.
|
|
*/
|
|
public boolean clearWorkLocation(WorkLocation wl) {
|
|
for (Unit u : wl.getUnitList()) {
|
|
WorkLocation w = find(wl.getColony().getCurrentWorkLocations(),
|
|
w2 -> w2 != wl && w2.canAdd(u));
|
|
if (w != null) u.setLocation(w);
|
|
}
|
|
return wl.isEmpty();
|
|
}
|
|
|
|
public static class MapBuilder{
|
|
|
|
// Required parameter
|
|
private final Game game;
|
|
|
|
private TileType[][] tileTypes = null;
|
|
private int width;
|
|
private int height;
|
|
private TileType baseTile;
|
|
private boolean exploredByAll;
|
|
private boolean initiated;
|
|
|
|
public MapBuilder(Game game){
|
|
this.game = game;
|
|
setStartingParams();
|
|
}
|
|
|
|
private void setStartingParams(){
|
|
width = 20;
|
|
height = 15;
|
|
baseTile = spec().getTileType("model.tile.plains");
|
|
exploredByAll = false;
|
|
initiated = false;
|
|
// set empty grid
|
|
if(tileTypes == null){
|
|
tileTypes = new TileType[width][height];
|
|
}
|
|
for (int x = 0; x < width; x++) {
|
|
for (int y = 0; y < height; y++) {
|
|
tileTypes[x][y] = null;
|
|
}
|
|
}
|
|
}
|
|
|
|
public MapBuilder setBaseTileType(TileType baseType){
|
|
if(baseType == null){
|
|
throw new NullPointerException("Base tile type cannot be null");
|
|
}
|
|
this.baseTile = baseType;
|
|
return this;
|
|
}
|
|
|
|
public MapBuilder setDimensions(int width, int heigth){
|
|
if(width <= 0){
|
|
throw new RuntimeException("Width must be positive");
|
|
}
|
|
if(heigth <= 0){
|
|
throw new RuntimeException("Heigth must be positive");
|
|
}
|
|
if(initiated){
|
|
throw new IllegalStateException("Cannot resize map after setting a tile");
|
|
}
|
|
this.width = width;
|
|
this.height = heigth;
|
|
this.tileTypes = new TileType[width][height];
|
|
return this;
|
|
}
|
|
|
|
public MapBuilder setExploredByAll(boolean exploredByAll){
|
|
this.exploredByAll = exploredByAll;
|
|
return this;
|
|
}
|
|
|
|
public MapBuilder setTileType(int x, int y, TileType tileType){
|
|
if(x < 0 || y < 0){
|
|
throw new RuntimeException("Coordenates cannot be negative");
|
|
}
|
|
if(x >= width || y >= height ){
|
|
throw new RuntimeException("Coordenate out of bounds");
|
|
}
|
|
if(tileType == null){
|
|
throw new NullPointerException("Tile type cannot be null");
|
|
}
|
|
|
|
tileTypes[x][y]= tileType;
|
|
initiated = true;
|
|
|
|
return this;
|
|
}
|
|
|
|
// Implementation method, completes grid by setting uninitialized tiles
|
|
//to the base tile type
|
|
private void completeWorkingGrid(){
|
|
for (int x = 0; x < width; x++) {
|
|
for (int y = 0; y < height; y++) {
|
|
// Already manually set by the tester
|
|
if(tileTypes[x][y] != null){
|
|
continue;
|
|
}
|
|
tileTypes[x][y] = baseTile;
|
|
}
|
|
}
|
|
initiated=true;
|
|
}
|
|
|
|
public Map build(){
|
|
completeWorkingGrid();
|
|
Map map = new Map(game, width, height);
|
|
Region region = new Region(game);
|
|
|
|
map.populateTiles((x, y) -> {
|
|
TileType tileType = tileTypes[x][y];
|
|
Tile t = new Tile(game, tileType, x, y);
|
|
t.setRegion(region);
|
|
return t;
|
|
});
|
|
|
|
map.resetContiguity();
|
|
map.resetHighSeasCount();
|
|
if (exploredByAll) {
|
|
map.forEachTile(t -> {
|
|
for (Player p : game.getLiveEuropeanPlayerList()) {
|
|
t.setExplored(p, true);
|
|
}
|
|
});
|
|
}
|
|
return map;
|
|
}
|
|
|
|
public MapBuilder reset() {
|
|
setStartingParams();
|
|
|
|
return this;
|
|
}
|
|
}
|
|
|
|
public static class IndianSettlementBuilder{
|
|
|
|
private static final String defaultIndianPlayer = "model.nation.tupi";
|
|
|
|
// Required parameter
|
|
private final Game game;
|
|
|
|
private Player indianPlayer;
|
|
private String skillTaught;
|
|
private int initialBravesInCamp;
|
|
private Tile settlementTile;
|
|
private static int settlementNumber = 1;
|
|
|
|
private boolean isCapital;
|
|
private Unit residentMissionary;
|
|
|
|
|
|
public IndianSettlementBuilder(Game game) {
|
|
this.game = game;
|
|
setStartingParams();
|
|
}
|
|
|
|
private void setStartingParams() {
|
|
// Some params can only be set in build(), because the
|
|
// default values may not be valid for the game set
|
|
// However, the tester himself may set them to valid values
|
|
// later, so they are set to null for now
|
|
indianPlayer = null;
|
|
initialBravesInCamp = 1;
|
|
settlementTile = null;
|
|
skillTaught = "model.unit.masterCottonPlanter";
|
|
isCapital = false;
|
|
residentMissionary = null;
|
|
}
|
|
|
|
public IndianSettlementBuilder player(Player player) {
|
|
if (player == null
|
|
|| none(game.getPlayers(matchKey(player)))) {
|
|
throw new RuntimeException("Indian player not in game");
|
|
}
|
|
this.indianPlayer = player;
|
|
return this;
|
|
}
|
|
|
|
public IndianSettlementBuilder initialBravesInCamp(int nBraves) {
|
|
if (nBraves <= 0) {
|
|
throw new RuntimeException("Number of braves must be positive");
|
|
}
|
|
this.initialBravesInCamp = nBraves;
|
|
return this;
|
|
}
|
|
|
|
public IndianSettlementBuilder settlementTile(Tile tile) {
|
|
Tile tileOnMap = this.game.getMap()
|
|
.getTile(tile.getX(), tile.getY());
|
|
if (tile != tileOnMap) {
|
|
throw new RuntimeException("Given tile not on map");
|
|
}
|
|
this.settlementTile = tile;
|
|
return this;
|
|
}
|
|
|
|
public IndianSettlementBuilder capital(boolean isCapital) {
|
|
this.isCapital = isCapital;
|
|
|
|
return this;
|
|
}
|
|
|
|
public IndianSettlementBuilder missionary(Unit missionary) {
|
|
this.residentMissionary = missionary;
|
|
|
|
return this;
|
|
}
|
|
|
|
public IndianSettlementBuilder skillToTeach(String skill) {
|
|
this.skillTaught = skill;
|
|
|
|
return this;
|
|
}
|
|
|
|
private String getSimpleName(Player player, boolean isCapital) {
|
|
return (isCapital) ? player.getName() + "-capital"
|
|
: "Settlement-" + settlementNumber++;
|
|
}
|
|
|
|
public IndianSettlement build() {
|
|
UnitType skillToTeach = null;
|
|
|
|
if (skillTaught != null) {
|
|
skillToTeach = spec().getUnitType(skillTaught);
|
|
}
|
|
|
|
// indianPlayer not set, get default
|
|
if (indianPlayer == null) {
|
|
indianPlayer = game.getPlayerByNationId(defaultIndianPlayer);
|
|
if (indianPlayer == null) {
|
|
throw new RuntimeException("Default Indian player "
|
|
+ defaultIndianPlayer + " not in game");
|
|
}
|
|
}
|
|
UnitType indianBraveType = spec().getDefaultUnitType(indianPlayer);
|
|
|
|
// settlement tile no set, get default
|
|
if (settlementTile == null) {
|
|
settlementTile = game.getMap().getTile(5, 8);
|
|
if (settlementTile == null) {
|
|
throw new RuntimeException("Default tile not in game");
|
|
}
|
|
}
|
|
|
|
IndianSettlement camp = new ServerIndianSettlement(game,
|
|
indianPlayer, getSimpleName(indianPlayer, isCapital),
|
|
settlementTile, isCapital, skillToTeach, residentMissionary);
|
|
indianPlayer.addSettlement(camp);
|
|
|
|
// Add braves
|
|
for (int i = 0; i < initialBravesInCamp; i++) {
|
|
Unit brave = new ServerUnit(game, camp, indianPlayer,
|
|
indianBraveType);
|
|
if (brave == null) {
|
|
throw new RuntimeException("Null brave");
|
|
}
|
|
camp.addOwnedUnit(brave);
|
|
}
|
|
camp.placeSettlement(true);
|
|
return camp;
|
|
}
|
|
|
|
public IndianSettlementBuilder reset() {
|
|
setStartingParams();
|
|
|
|
return this;
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
* Set the production bonus of the given colony to the given
|
|
* value.
|
|
*
|
|
* @param colony a {@code Colony} value
|
|
* @param value an {@code int} value
|
|
*/
|
|
public void setProductionBonus(Colony colony, int value) {
|
|
Field productionBonus;
|
|
try {
|
|
productionBonus = Colony.class.getDeclaredField("productionBonus");
|
|
productionBonus.setAccessible(true);
|
|
productionBonus.setInt(colony, value);
|
|
colony.invalidateCache();
|
|
} catch (NoSuchFieldException|IllegalAccessException ex) {
|
|
fail(ex.toString());
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Build/place a colony with a unit, without requiring the server.
|
|
*/
|
|
public void nonServerBuildColony(Unit builder, Colony colony) {
|
|
colony.placeSettlement(true);//-vis
|
|
colony.getOwner().invalidateCanSeeTiles();//+vis
|
|
nonServerJoinColony(builder, colony);
|
|
}
|
|
|
|
/**
|
|
* Join a colony with a unit, without requiring the server.
|
|
*/
|
|
public void nonServerJoinColony(Unit builder, Colony colony) {
|
|
builder.setLocation(colony);
|
|
builder.setMovesLeft(0);
|
|
}
|
|
|
|
/**
|
|
* Repeatedly ask the CombatModel for an attack result until it
|
|
* gives the primary one we want (WIN, LOSE, NO_RESULT).
|
|
*/
|
|
public List<CombatResult> fakeAttackResult(CombatResult result,
|
|
FreeColGameObject attacker,
|
|
FreeColGameObject defender)
|
|
{
|
|
List<CombatResult> crs;
|
|
final double delta = 0.02;
|
|
CombatModel combatModel = getGame().getCombatModel();
|
|
CombatOdds combatOdds = combatModel.calculateCombatOdds(attacker, defender);
|
|
double p = combatOdds.win;
|
|
MockPseudoRandom mr = new MockPseudoRandom();
|
|
List<Integer> number = new ArrayList<>();
|
|
number.add(-1);
|
|
do {
|
|
p += (result == CombatResult.WIN) ? -delta : delta;
|
|
if (p < 0.0 || p >= 1.0) {
|
|
throw new IllegalStateException("f out of range: "
|
|
+ Double.toString(p));
|
|
}
|
|
number.set(0, (int)(Integer.MAX_VALUE * p));
|
|
mr.setNextNumbers(number, true);
|
|
crs = combatModel.generateAttackResult(mr, attacker, defender);
|
|
} while (crs.get(0) != result);
|
|
return crs;
|
|
}
|
|
|
|
/**
|
|
* Check a combat result list.
|
|
*
|
|
* @param name A base string for the error message.
|
|
* @param crs The list of {@code CombatResult} to check.
|
|
* @param results The expected {@code CombatResult}s.
|
|
*/
|
|
public void checkCombat(String name, List<CombatResult> crs,
|
|
CombatResult... results) {
|
|
int i = 0;
|
|
for (CombatResult cr : results) {
|
|
CombatResult expect = (i < crs.size()) ? crs.get(i) : null;
|
|
if (expect != cr) break;
|
|
i++;
|
|
}
|
|
if (i == results.length) {
|
|
if (crs.size() == i) return;
|
|
i++;
|
|
}
|
|
String err = name + ", failed at " + i + ":";
|
|
for (CombatResult cr : results) {
|
|
err += " " + cr;
|
|
}
|
|
err += " !=";
|
|
for (CombatResult cr : crs) {
|
|
err += " " + cr;
|
|
}
|
|
fail(err);
|
|
}
|
|
|
|
/**
|
|
* Check a list of goods.
|
|
*
|
|
* @param err A base string for the error message.
|
|
* @param goods A list of expected {@code AbstractGoods} to check.
|
|
* @param results The expected {@code AbstractGoods}.
|
|
*/
|
|
public void checkGoods(String err, List<AbstractGoods> goods,
|
|
AbstractGoods... results) {
|
|
List<AbstractGoods> check = new ArrayList<>(goods);
|
|
for (AbstractGoods ag : results) {
|
|
assertTrue(err + " requires " + ag, check.contains(ag));
|
|
check.remove(ag);
|
|
}
|
|
assertTrue(err + " requires more goods", check.isEmpty());
|
|
}
|
|
|
|
public void addUnitTypeChange(String type, UnitType from, UnitType to,
|
|
int probability, int turns) {
|
|
UnitTypeChange utc = new UnitTypeChange(type + "."
|
|
+ from.getSuffix() + "-" + to.getSuffix(), spec());
|
|
utc.from = from;
|
|
utc.to = to;
|
|
utc.probability = probability;
|
|
utc.turns = turns;
|
|
UnitChangeType uct = spec().getUnitChangeType(type);
|
|
if (uct == null) {
|
|
uct = new UnitChangeType(type, spec());
|
|
spec().getUnitChangeTypeList().add(uct);
|
|
}
|
|
uct.addUnitTypeChange(utc);
|
|
}
|
|
|
|
/**
|
|
* Helper function to get a server player by id.
|
|
*
|
|
* @param game The {@code Game} to look in.
|
|
* @param id The player identifier.
|
|
* @return The {@code ServerPlayer} found.
|
|
*/
|
|
public ServerPlayer getServerPlayer(Game game, String id) {
|
|
return (ServerPlayer)game.getPlayerByNationId(id);
|
|
}
|
|
}
|