001/* 002 * Gridarta MMORPG map editor for Crossfire, Daimonin and similar games. 003 * Copyright (C) 2000-2011 The Gridarta Developers. 004 * 005 * This program is free software; you can redistribute it and/or modify 006 * it under the terms of the GNU General Public License as published by 007 * the Free Software Foundation; either version 2 of the License, or 008 * (at your option) any later version. 009 * 010 * This program is distributed in the hope that it will be useful, 011 * but WITHOUT ANY WARRANTY; without even the implied warranty of 012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 013 * GNU General Public License for more details. 014 * 015 * You should have received a copy of the GNU General Public License along 016 * with this program; if not, write to the Free Software Foundation, Inc., 017 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 018 */ 019 020package net.sf.gridarta.actions; 021 022import java.awt.Point; 023import java.io.File; 024import net.sf.gridarta.model.archetype.DuplicateArchetypeException; 025import net.sf.gridarta.model.archetype.TestArchetype; 026import net.sf.gridarta.model.baseobject.BaseObject; 027import net.sf.gridarta.model.exitconnector.ExitConnectorModel; 028import net.sf.gridarta.model.exitconnector.ExitLocation; 029import net.sf.gridarta.model.exitconnector.TestExitConnectorModel; 030import net.sf.gridarta.model.gameobject.TestGameObject; 031import net.sf.gridarta.model.maparchobject.TestMapArchObject; 032import net.sf.gridarta.model.mapcontrol.MapControl; 033import net.sf.gridarta.model.mapcontrol.TestMapControlCreator; 034import net.sf.gridarta.model.mapmanager.TestFileControl; 035import net.sf.gridarta.model.mapmodel.CannotInsertGameObjectException; 036import net.sf.gridarta.model.mapmodel.MapModel; 037import net.sf.gridarta.model.mapmodel.TestMapModelHelper; 038import net.sf.gridarta.utils.Size2D; 039import org.jetbrains.annotations.NotNull; 040import org.jetbrains.annotations.Nullable; 041import org.junit.Assert; 042import org.junit.Before; 043import org.junit.Test; 044 045/** 046 * Regression tests for {@link ExitConnectorActions}. 047 * @author Andreas Kirschbaum 048 */ 049public class ExitConnectorActionsTest { 050 051 /** 052 * The first map file. 053 */ 054 private static final File MAP_FILE1 = new File("a"); 055 056 /** 057 * The first map name. 058 */ 059 private static final String MAP_NAME1 = "name1"; 060 061 /** 062 * The second map file. 063 */ 064 private static final File MAP_FILE2 = new File("b"); 065 066 /** 067 * The second map name. 068 */ 069 private static final String MAP_NAME2 = "name2"; 070 071 /** 072 * The {@link TestMapControlCreator} for creating maps. 073 */ 074 @Nullable 075 private TestMapControlCreator testMapControlCreator; 076 077 /** 078 * The {@link TestMapModelHelper} instance. 079 */ 080 @Nullable 081 private TestMapModelHelper mapModelHelper; 082 083 /** 084 * Checks that {@link ExitConnectorActions#doExitCopy(boolean, MapControl, 085 * Point)} does work. 086 */ 087 @Test 088 public void testExitCopy1() { 089 final ExitConnectorModel model = new TestExitConnectorModel(); 090 final ExitConnectorActions<TestGameObject, TestMapArchObject, TestArchetype> actions = createActions(model); 091 final Size2D mapSize = new Size2D(5, 5); 092 assert testMapControlCreator != null; 093 final MapControl<TestGameObject, TestMapArchObject, TestArchetype> mapControl = testMapControlCreator.newMapControl(MAP_FILE1, MAP_NAME1, mapSize); 094 095 // active ==> enabled 096 final Point point1 = new Point(3, 4); 097 Assert.assertTrue(actions.doExitCopy(false, mapControl, point1)); 098 Assert.assertNull(model.getExitLocation()); 099 100 // perform copy 101 Assert.assertTrue(actions.doExitCopy(true, mapControl, point1)); 102 assert testMapControlCreator != null; 103 Assert.assertEquals(new ExitLocation(MAP_FILE1, point1, MAP_NAME1, testMapControlCreator.getPathManager()), model.getExitLocation()); 104 105 // unsaved map ==> disabled 106 mapControl.getMapModel().setMapFile(null); 107 Assert.assertFalse(actions.doExitCopy(false, mapControl, point1)); 108 assert testMapControlCreator != null; 109 Assert.assertEquals(new ExitLocation(MAP_FILE1, point1, MAP_NAME1, testMapControlCreator.getPathManager()), model.getExitLocation()); // disabled -> unchanged model 110 } 111 112 /** 113 * Checks that {@link ExitConnectorActions#doExitPaste(boolean, MapControl, 114 * Point)} does work. 115 * @throws CannotInsertGameObjectException if the test fails 116 */ 117 @Test 118 public void testExitPaste1() throws CannotInsertGameObjectException { 119 final ExitConnectorModel model = new TestExitConnectorModel(); 120 final ExitConnectorActions<TestGameObject, TestMapArchObject, TestArchetype> actions = createActions(model); 121 final Size2D mapSize = new Size2D(5, 5); 122 assert testMapControlCreator != null; 123 final MapControl<TestGameObject, TestMapArchObject, TestArchetype> mapControl = testMapControlCreator.newMapControl(MAP_FILE1, MAP_NAME1, mapSize); 124 final MapModel<TestGameObject, TestMapArchObject, TestArchetype> mapModel = mapControl.getMapModel(); 125 126 final Point point1 = new Point(3, 4); 127 final Point point2 = new Point(1, 2); 128 129 assert testMapControlCreator != null; 130 model.setExitLocation(new ExitLocation(MAP_FILE2, point2, MAP_NAME2, testMapControlCreator.getPathManager())); 131 132 // no exit at cursor and no auto-create ==> disabled 133 Assert.assertFalse(actions.doExitPaste(false, mapControl, point1)); 134 135 mapModel.beginTransaction("TEST"); 136 try { 137 assert mapModelHelper != null; 138 mapModelHelper.insertFloor(mapModel, point1); 139 } finally { 140 mapModel.endTransaction(); 141 } 142 143 // no exit at cursor and no auto-create ==> disabled 144 Assert.assertFalse(actions.doExitPaste(false, mapControl, point1)); 145 146 mapModel.beginTransaction("TEST"); 147 try { 148 assert mapModelHelper != null; 149 mapModelHelper.insertExit(mapModel, point1); 150 } finally { 151 mapModel.endTransaction(); 152 } 153 154 // exit at cursor ==> enabled 155 Assert.assertTrue(actions.doExitPaste(false, mapControl, point1)); 156 checkExit(mapModel, point1, 1, "", new Point(0, 0)); // "check only" ==> exit is unchanged 157 158 // perform paste 159 Assert.assertTrue(actions.doExitPaste(true, mapControl, point1)); 160 checkExit(mapModel, point1, 1, "b", point2); 161 } 162 163 /** 164 * Checks that {@link ExitConnectorActions#doExitPaste(boolean, MapControl, 165 * Point)} does not crash when connecting to an unsaved map. 166 */ 167 @Test 168 public void testExitPaste2() { 169 final ExitConnectorModel model = new TestExitConnectorModel(); 170 final ExitConnectorActions<TestGameObject, TestMapArchObject, TestArchetype> actions = createActions(model); 171 final Size2D mapSize = new Size2D(5, 5); 172 173 assert testMapControlCreator != null; 174 final MapControl<TestGameObject, TestMapArchObject, TestArchetype> mapControl1 = testMapControlCreator.newMapControl(MAP_FILE1, MAP_NAME1, mapSize); 175 final MapModel<TestGameObject, TestMapArchObject, TestArchetype> mapModel1 = mapControl1.getMapModel(); 176 177 final Point point1 = new Point(3, 4); 178 final Point point2 = new Point(1, 2); 179 180 assert testMapControlCreator != null; 181 model.setExitLocation(new ExitLocation(MAP_FILE2, point2, MAP_NAME2, testMapControlCreator.getPathManager())); 182 183 model.setAutoCreateExit(true); 184 185 // copy must fail for unsaved map 186 mapModel1.setMapFile(null); // pretend unsaved map 187 Assert.assertFalse(actions.doExitCopy(true, mapControl1, point1)); 188 189 // paste must succeed for unsaved map 190 Assert.assertTrue(actions.doExitPaste(true, mapControl1, point1)); 191 } 192 193 /** 194 * Checks that {@link ExitConnectorActions#doExitConnect(boolean, 195 * MapControl, Point)} does work. 196 * @throws CannotInsertGameObjectException if the test fails 197 */ 198 @Test 199 public void testExitConnect1() throws CannotInsertGameObjectException { 200 final ExitConnectorModel model = new TestExitConnectorModel(); 201 final ExitConnectorActions<TestGameObject, TestMapArchObject, TestArchetype> actions = createActions(model); 202 203 final Size2D mapSize = new Size2D(5, 5); 204 assert testMapControlCreator != null; 205 final MapControl<TestGameObject, TestMapArchObject, TestArchetype> mapControl1 = testMapControlCreator.newMapControl(MAP_FILE1, MAP_NAME1, mapSize); 206 final MapModel<TestGameObject, TestMapArchObject, TestArchetype> mapModel1 = mapControl1.getMapModel(); 207 208 assert testMapControlCreator != null; 209 final MapControl<TestGameObject, TestMapArchObject, TestArchetype> mapControl2 = testMapControlCreator.newMapControl(MAP_FILE2, MAP_NAME2, mapSize); 210 final MapModel<TestGameObject, TestMapArchObject, TestArchetype> mapModel2 = mapControl2.getMapModel(); 211 212 final Point point1 = new Point(3, 4); 213 final Point point2 = new Point(1, 2); 214 215 assert testMapControlCreator != null; 216 model.setExitLocation(new ExitLocation(MAP_FILE2, point2, MAP_NAME2, testMapControlCreator.getPathManager())); 217 218 // no exit at cursor and no auto-create ==> disabled 219 Assert.assertFalse(actions.doExitConnect(false, mapControl1, point1)); 220 221 mapModel1.beginTransaction("TEST"); 222 try { 223 assert mapModelHelper != null; 224 mapModelHelper.insertFloor(mapModel1, point1); 225 } finally { 226 mapModel1.endTransaction(); 227 } 228 229 // no exit at cursor and no auto-create ==> disabled 230 Assert.assertFalse(actions.doExitConnect(false, mapControl1, point1)); 231 232 mapModel1.beginTransaction("TEST"); 233 try { 234 assert mapModelHelper != null; 235 mapModelHelper.insertExit(mapModel1, point1); 236 } finally { 237 mapModel1.endTransaction(); 238 } 239 240 // no exit at source and no auto-create ==> disabled 241 Assert.assertFalse(actions.doExitConnect(false, mapControl1, point1)); 242 243 mapModel2.beginTransaction("TEST"); 244 try { 245 assert mapModelHelper != null; 246 mapModelHelper.insertExit(mapModel2, point2); 247 } finally { 248 mapModel2.endTransaction(); 249 } 250 251 // exit at source and cursor ==> enabled 252 Assert.assertTrue(actions.doExitConnect(false, mapControl1, point1)); 253 checkExit(mapModel1, point1, 1, "", new Point(0, 0)); // "check only" ==> exit is unchanged 254 checkExit(mapModel2, point2, 0, "", new Point(0, 0)); 255 256 // perform connect 257 Assert.assertTrue(actions.doExitConnect(true, mapControl1, point1)); 258 checkExit(mapModel1, point1, 1, "b", point2); 259 checkExit(mapModel2, point2, 0, "a", point1); 260 } 261 262 /** 263 * Checks that {@link ExitConnectorActions#doExitConnect(boolean, 264 * MapControl, Point)} does work when auto-creating exit objects. 265 */ 266 @Test 267 public void testExitConnectAuto1() { 268 final ExitConnectorModel model = new TestExitConnectorModel(); 269 final ExitConnectorActions<TestGameObject, TestMapArchObject, TestArchetype> actions = createActions(model); 270 271 final Size2D mapSize = new Size2D(5, 5); 272 assert testMapControlCreator != null; 273 final MapControl<TestGameObject, TestMapArchObject, TestArchetype> mapControl1 = testMapControlCreator.newMapControl(MAP_FILE1, MAP_NAME1, mapSize); 274 final MapModel<TestGameObject, TestMapArchObject, TestArchetype> mapModel1 = mapControl1.getMapModel(); 275 276 assert testMapControlCreator != null; 277 final MapControl<TestGameObject, TestMapArchObject, TestArchetype> mapControl2 = testMapControlCreator.newMapControl(MAP_FILE2, MAP_NAME2, mapSize); 278 final MapModel<TestGameObject, TestMapArchObject, TestArchetype> mapModel2 = mapControl2.getMapModel(); 279 280 final Point point1 = new Point(3, 4); 281 final Point point2 = new Point(1, 2); 282 283 assert testMapControlCreator != null; 284 model.setExitLocation(new ExitLocation(MAP_FILE2, point2, MAP_NAME2, testMapControlCreator.getPathManager())); 285 model.setAutoCreateExit(true); 286 287 model.setExitArchetypeName("undefined"); 288 289 // fails due to undefined archetype 290 Assert.assertFalse(actions.doExitConnect(true, mapControl1, point1)); 291 checkExit(mapModel1, point1, 0, null, null); 292 checkExit(mapModel2, point2, 0, null, null); 293 294 model.setExitArchetypeName("exit"); 295 296 // perform connect 297 Assert.assertTrue(actions.doExitConnect(true, mapControl1, point1)); 298 checkExit(mapModel1, point1, 0, "b", point2); 299 checkExit(mapModel2, point2, 0, "a", point1); 300 301 // perform connect; auto-create will re-use existing objects 302 Assert.assertTrue(actions.doExitConnect(true, mapControl1, point1)); 303 checkExit(mapModel1, point1, 0, "b", point2); 304 checkExit(mapModel1, point1, 1, null, null); 305 checkExit(mapModel2, point2, 0, "a", point1); 306 checkExit(mapModel2, point2, 1, null, null); 307 } 308 309 /** 310 * Checks that exit paths are correctly generated. 311 * @throws CannotInsertGameObjectException if the test fails 312 */ 313 @Test 314 public void testPath1() throws CannotInsertGameObjectException { 315 // both root ==> relative 316 testPath("/a", "/b", "b"); // both root ==> relative 317 318 // to or from root ==> absolute 319 testPath("/HallOfSelection", "/world/world_104_115", "/world/world_104_115"); 320 testPath("/world/world_104_115", "/HallOfSelection", "/HallOfSelection"); 321 322 // same top-level component ==> relative 323 testPath("/a/b/c/d", "/a/d/e", "../../d/e"); 324 testPath("/a/b/c/d", "/a/b/d", "../d"); 325 testPath("/a/b/c", "/a/b/d", "d"); 326 testPath("/a/b/c", "/a/b/c/d", "c/d"); 327 328 // else ==> absolute 329 testPath("/a/b/c", "/b/c/d", "/b/c/d"); 330 testPath("/a/b", "/b", "/b"); 331 testPath("/a", "/b/c", "/b/c"); 332 } 333 334 /** 335 * Checks that an exit path is correctly generated. 336 * @param mapPathFrom the map path to connect from; this map contains the 337 * exit object 338 * @param mapPathTo the map path to connect to 339 * @param expectedExitPath the expected map in the exit object 340 * @throws CannotInsertGameObjectException if the test fails 341 */ 342 private void testPath(@NotNull final String mapPathFrom, @NotNull final String mapPathTo, @NotNull final String expectedExitPath) throws CannotInsertGameObjectException { 343 final ExitConnectorModel model = new TestExitConnectorModel(); 344 final ExitConnectorActions<TestGameObject, TestMapArchObject, TestArchetype> actions = createActions(model); 345 346 assert testMapControlCreator != null; 347 final File mapDir = testMapControlCreator.getProjectSettings().getMapsDirectory(); 348 final File mapFileFrom = new File(mapDir, mapPathFrom); 349 final File mapFileTo = new File(mapDir, mapPathTo); 350 351 final Size2D mapSize = new Size2D(5, 5); 352 assert testMapControlCreator != null; 353 final MapControl<TestGameObject, TestMapArchObject, TestArchetype> mapControl = testMapControlCreator.newMapControl(mapFileFrom, MAP_NAME1, mapSize); 354 final MapModel<TestGameObject, TestMapArchObject, TestArchetype> mapModel = mapControl.getMapModel(); 355 356 final Point pointFrom = new Point(3, 4); 357 final Point pointTo = new Point(1, 2); 358 359 assert testMapControlCreator != null; 360 model.setExitLocation(new ExitLocation(mapFileTo, pointTo, MAP_NAME2, testMapControlCreator.getPathManager())); 361 mapModel.beginTransaction("TEST"); 362 try { 363 assert mapModelHelper != null; 364 mapModelHelper.insertExit(mapModel, pointFrom); 365 } finally { 366 mapModel.endTransaction(); 367 } 368 369 // perform connect 370 Assert.assertTrue(actions.doExitPaste(true, mapControl, pointFrom)); 371 checkExit(mapModel, pointFrom, 0, expectedExitPath, pointTo); 372 } 373 374 /** 375 * Initializes the test case. 376 * @throws DuplicateArchetypeException if the test case fails 377 */ 378 @Before 379 public void setUp() throws DuplicateArchetypeException { 380 testMapControlCreator = new TestMapControlCreator(); 381 mapModelHelper = testMapControlCreator.newMapModelCreator(); 382 } 383 384 /** 385 * Creates a new {@link ExitConnectorActions} instance. 386 * @param model the exit connector model to use 387 * @return the new exit connector actions instance 388 */ 389 private ExitConnectorActions<TestGameObject, TestMapArchObject, TestArchetype> createActions(@NotNull final ExitConnectorModel model) { 390 final TestMapControlCreator tmpTestMapControlCreator = testMapControlCreator; 391 assert tmpTestMapControlCreator != null; 392 return new ExitConnectorActions<TestGameObject, TestMapArchObject, TestArchetype>(model, tmpTestMapControlCreator.getExitMatcher(), tmpTestMapControlCreator.getArchetypeSet(), tmpTestMapControlCreator.getMapManager(), new TestFileControl(), tmpTestMapControlCreator.getPathManager(), tmpTestMapControlCreator.getInsertionModeSet()); 393 } 394 395 /** 396 * Checks that a map model contains an exit game object. 397 * @param mapModel the map model to check 398 * @param point the position to check 399 * @param index the index to check 400 * @param exitPath the expected exit path or <code>null</code> if no exit 401 * game object is expected 402 * @param exitPoint the expected exit destination or <code>null</code> if no 403 * exit game object is expected 404 */ 405 private static void checkExit(@NotNull final MapModel<TestGameObject, TestMapArchObject, TestArchetype> mapModel, @NotNull final Point point, final int index, @Nullable final String exitPath, @Nullable final Point exitPoint) { 406 int thisIndex = 0; 407 for (final BaseObject<?, ?, ?, ?> gameObject : mapModel.getMapSquare(point)) { 408 if (thisIndex == index) { 409 if (gameObject.getTypeNo() != TestMapModelHelper.EXIT_TYPE) { 410 break; 411 } 412 413 if (exitPath == null || exitPoint == null) { 414 Assert.fail("exit found but none expected"); 415 throw new AssertionError(); 416 } 417 418 Assert.assertEquals(exitPath, gameObject.getAttributeString(BaseObject.SLAYING)); 419 Assert.assertEquals(exitPoint.x, gameObject.getAttributeInt(BaseObject.HP)); 420 Assert.assertEquals(exitPoint.y, gameObject.getAttributeInt(BaseObject.SP)); 421 return; 422 } 423 424 thisIndex++; 425 } 426 427 if (exitPath != null || exitPoint != null) { 428 Assert.fail("no exit found"); 429 } 430 } 431 432}