001/*
002 * Gridarta MMORPG map editor for Crossfire, Daimonin and similar games.
003 * Copyright (C) 2000-2010 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.var.crossfire.model.gameobject;
021
022import java.util.Iterator;
023import net.sf.gridarta.model.baseobject.GameObjectContainer;
024import net.sf.gridarta.var.crossfire.model.archetype.Archetype;
025import net.sf.gridarta.var.crossfire.model.maparchobject.MapArchObject;
026import org.jetbrains.annotations.NotNull;
027import org.junit.Assert;
028import org.junit.Test;
029
030/**
031 * Checks that {@link GameObjectContainer GameObjectContainers} correctly
032 * propagate elevation information when being modified.
033 * @author Andreas Kirschbaum
034 */
035public class PropagateElevationTest {
036
037    /**
038     * Checks that {@link GameObjectContainer#addFirst(net.sf.gridarta.model.gameobject.GameObject)}
039     * does work correctly.
040     */
041    @Test
042    public void testAddFirst() {
043        final GameObjectCreator gameObjectCreator = new GameObjectCreator();
044        final GameObjectContainer<GameObject, MapArchObject, Archetype> gameObjectContainer = gameObjectCreator.newGameObject(0);
045
046        // first game object => keep
047        gameObjectContainer.addFirst(gameObjectCreator.newGameObject(123));
048        check(gameObjectContainer, 123);
049
050        // without elevation => propagate
051        gameObjectContainer.addFirst(gameObjectCreator.newGameObject(0));
052        check(gameObjectContainer, 123);
053
054        // with elevation => ignore but propagate
055        gameObjectContainer.addFirst(gameObjectCreator.newGameObject(321));
056        check(gameObjectContainer, 123);
057    }
058
059    /**
060     * Checks that {@link GameObjectContainer#addLast(net.sf.gridarta.model.gameobject.GameObject)}
061     * does work correctly.
062     */
063    @Test
064    public void testAddLast() {
065        final GameObjectCreator gameObjectCreator = new GameObjectCreator();
066        final GameObjectContainer<GameObject, MapArchObject, Archetype> gameObjectContainer = gameObjectCreator.newGameObject(0);
067
068        // first game object => keep
069        gameObjectContainer.addLast(gameObjectCreator.newGameObject(123));
070        check(gameObjectContainer, 123);
071
072        // without elevation => keep
073        gameObjectContainer.addLast(gameObjectCreator.newGameObject(0));
074        check(gameObjectContainer, 123, 0);
075
076        // with elevation => keep
077        gameObjectContainer.addLast(gameObjectCreator.newGameObject(321));
078        check(gameObjectContainer, 123, 0, 321);
079    }
080
081    /**
082     * Checks that {@link GameObjectContainer#insertBefore(net.sf.gridarta.model.gameobject.GameObject,
083     * net.sf.gridarta.model.gameobject.GameObject)} does work correctly.
084     */
085    @Test
086    public void testInsertBefore() {
087        final GameObjectCreator gameObjectCreator = new GameObjectCreator();
088        final GameObjectContainer<GameObject, MapArchObject, Archetype> gameObjectContainer = gameObjectCreator.newGameObject(0);
089
090        // first game object => keep
091        gameObjectContainer.insertBefore(gameObjectCreator.newGameObject(1), null);
092        check(gameObjectContainer, 1);
093
094        // without elevation => propagate
095        gameObjectContainer.insertBefore(gameObjectCreator.newGameObject(0), null);
096        check(gameObjectContainer, 1, 0);
097
098        // with elevation => ignore but propagate
099        final GameObject ob1 = gameObjectCreator.newGameObject(2);
100        gameObjectContainer.insertBefore(ob1, null);
101        check(gameObjectContainer, 1, 0, 0);
102
103        // with elevation => keep
104        gameObjectContainer.insertBefore(gameObjectCreator.newGameObject(3), ob1);
105        check(gameObjectContainer, 1, 3, 0, 0);
106
107        // with elevation => ignore but propagate
108        gameObjectContainer.insertBefore(gameObjectCreator.newGameObject(4), null);
109        check(gameObjectContainer, 1, 0, 3, 0, 0);
110    }
111
112    /**
113     * Checks that {@link GameObjectContainer#insertAfter(net.sf.gridarta.model.gameobject.GameObject,
114     * net.sf.gridarta.model.gameobject.GameObject)} does work correctly.
115     */
116    @Test
117    public void testInsertAfter() {
118        final GameObjectCreator gameObjectCreator = new GameObjectCreator();
119        final GameObjectContainer<GameObject, MapArchObject, Archetype> gameObjectContainer = gameObjectCreator.newGameObject(0);
120
121        // first game object => keep
122        gameObjectContainer.insertAfter(null, gameObjectCreator.newGameObject(1));
123        check(gameObjectContainer, 1);
124
125        // at end => keep
126        final GameObject ob1 = gameObjectCreator.newGameObject(2);
127        gameObjectContainer.insertAfter(null, ob1);
128        check(gameObjectContainer, 1, 2);
129
130        // at front, without elevation => propagate
131        gameObjectContainer.insertAfter(ob1, gameObjectCreator.newGameObject(0));
132        check(gameObjectContainer, 1, 0, 2);
133
134        // middle => keep
135        gameObjectContainer.insertAfter(ob1, gameObjectCreator.newGameObject(3));
136        check(gameObjectContainer, 1, 0, 3, 2);
137
138        // at front, with elevation => ignore but propagate
139        gameObjectContainer.insertAfter(gameObjectContainer.getFirst(), gameObjectCreator.newGameObject(4));
140        check(gameObjectContainer, 1, 0, 0, 3, 2);
141    }
142
143    /**
144     * Checks that {@link GameObjectContainer#moveBottom(net.sf.gridarta.model.gameobject.GameObject)}
145     * does work correctly.
146     */
147    @Test
148    public void testMoveBottom() {
149        final GameObjectCreator gameObjectCreator = new GameObjectCreator();
150        final GameObjectContainer<GameObject, MapArchObject, Archetype> container1 = newContainer(gameObjectCreator, 1, 0, 0, 0);
151        container1.moveBottom(get(container1, 0));
152        check(container1, 1, 0, 0, 0);
153        container1.moveBottom(get(container1, 1));
154        check(container1, 1, 0, 0, 0);
155        container1.moveBottom(get(container1, 3));
156        check(container1, 1, 0, 0, 0);
157    }
158
159    /**
160     * Checks that {@link GameObjectContainer#moveDown(net.sf.gridarta.model.gameobject.GameObject)}
161     * does work correctly.
162     */
163    @Test
164    public void testMoveDown() {
165        final GameObjectCreator gameObjectCreator = new GameObjectCreator();
166        final GameObjectContainer<GameObject, MapArchObject, Archetype> container1 = newContainer(gameObjectCreator, 1, 0, 0, 0);
167        container1.moveDown(get(container1, 0));
168        check(container1, 1, 0, 0, 0);
169        container1.moveDown(get(container1, 1));
170        check(container1, 1, 0, 0, 0);
171        container1.moveDown(get(container1, 3));
172        check(container1, 1, 0, 0, 0);
173    }
174
175    /**
176     * Checks that {@link GameObjectContainer#moveUp(net.sf.gridarta.model.gameobject.GameObject)}
177     * does work correctly.
178     */
179    @Test
180    public void testMoveUp() {
181        final GameObjectCreator gameObjectCreator = new GameObjectCreator();
182        final GameObjectContainer<GameObject, MapArchObject, Archetype> container1 = newContainer(gameObjectCreator, 1, 0, 0, 0);
183        container1.moveUp(get(container1, 0));
184        check(container1, 1, 0, 0, 0);
185        container1.moveUp(get(container1, 1));
186        check(container1, 1, 0, 0, 0);
187        container1.moveUp(get(container1, 3));
188        check(container1, 1, 0, 0, 0);
189    }
190
191    /**
192     * Checks that {@link GameObjectContainer#moveTop(net.sf.gridarta.model.gameobject.GameObject)}
193     * does work correctly.
194     */
195    @Test
196    public void testMoveTop() {
197        final GameObjectCreator gameObjectCreator = new GameObjectCreator();
198        final GameObjectContainer<GameObject, MapArchObject, Archetype> container1 = newContainer(gameObjectCreator, 1, 0, 0, 0);
199        container1.moveTop(get(container1, 0));
200        check(container1, 1, 0, 0, 0);
201        container1.moveTop(get(container1, 1));
202        check(container1, 1, 0, 0, 0);
203        container1.moveTop(get(container1, 3));
204        check(container1, 1, 0, 0, 0);
205    }
206
207    /**
208     * Checks that {@link GameObjectContainer#remove(net.sf.gridarta.model.gameobject.GameObject)}
209     * does work correctly.
210     */
211    @Test
212    public void testRemove() {
213        final GameObjectCreator gameObjectCreator = new GameObjectCreator();
214        final GameObjectContainer<GameObject, MapArchObject, Archetype> container1 = newContainer(gameObjectCreator, 1, 0, 0, 0);
215        container1.remove(get(container1, 0));
216        check(container1, 1, 0, 0);
217        container1.remove(get(container1, 2));
218        check(container1, 1, 0);
219        container1.remove(get(container1, 0));
220        check(container1, 1);
221        container1.remove(get(container1, 0));
222        check(container1);
223    }
224
225    /**
226     * Checks that {@link GameObjectContainer#replace(net.sf.gridarta.model.gameobject.GameObject,
227     * net.sf.gridarta.model.gameobject.GameObject)} does work correctly.
228     */
229    @Test
230    public void testReplace() {
231        final GameObjectCreator gameObjectCreator = new GameObjectCreator();
232        final GameObjectContainer<GameObject, MapArchObject, Archetype> container1 = newContainer(gameObjectCreator, 1, 0, 0, 0);
233        container1.replace(get(container1, 0), gameObjectCreator.newGameObject(2));
234        check(container1, 1, 0, 0, 0);
235        container1.replace(get(container1, 1), gameObjectCreator.newGameObject(3));
236        check(container1, 1, 3, 0, 0);
237        container1.replace(get(container1, 0), gameObjectCreator.newGameObject(4));
238        check(container1, 1, 3, 0, 0);
239    }
240
241    /**
242     * Checks that {@link GameObjectContainer#iterator()}'s {@link
243     * Iterator#remove()} does work correctly.
244     */
245    @Test
246    public void testIterator() {
247        final GameObjectCreator gameObjectCreator = new GameObjectCreator();
248        final GameObjectContainer<GameObject, MapArchObject, Archetype> container1 = newContainer(gameObjectCreator, 1, 0, 0, 0, 0, 0);
249        final Iterator<GameObject> it = container1.iterator();
250        it.next();
251        it.remove();
252        check(container1, 1, 0, 0, 0, 0);
253        it.next();
254        it.remove();
255        check(container1, 1, 0, 0, 0);
256        it.next();
257        it.next();
258        it.remove();
259        check(container1, 1, 0, 0);
260    }
261
262    /**
263     * Checks that {@link GameObjectContainer#reverse()}'s {@link
264     * Iterator#remove()} does work correctly.
265     */
266    @Test
267    public void testReverse() {
268        final GameObjectCreator gameObjectCreator = new GameObjectCreator();
269        final GameObjectContainer<GameObject, MapArchObject, Archetype> container1 = newContainer(gameObjectCreator, 1, 0, 0, 0, 0, 0);
270        final Iterator<GameObject> it = container1.reverse().iterator();
271        it.next();
272        it.remove();
273        check(container1, 1, 0, 0, 0, 0);
274        it.next();
275        it.remove();
276        check(container1, 1, 0, 0, 0);
277        it.next();
278        it.next();
279        it.remove();
280        check(container1, 1, 0, 0);
281        it.next();
282        it.remove();
283        check(container1, 1, 0);
284        it.next();
285        it.remove();
286        check(container1, 1);
287        Assert.assertFalse(it.hasNext());
288    }
289
290    /**
291     * Creates a new {@link GameObjectContainer} that contains game objects with
292     * the given elevation values.
293     * @param gameObjectCreator the game object creator to use
294     * @param elevations the elevations
295     * @return the game object container
296     */
297    @NotNull
298    private static GameObjectContainer<GameObject, MapArchObject, Archetype> newContainer(@NotNull final GameObjectCreator gameObjectCreator, final int... elevations) {
299        final GameObjectContainer<GameObject, MapArchObject, Archetype> gameObject = gameObjectCreator.newGameObject(0);
300        for (final int elevation : elevations) {
301            gameObject.addLast(gameObjectCreator.newGameObject(elevation));
302        }
303        return gameObject;
304    }
305
306    /**
307     * Returns the game object at a given index.
308     * @param gameObjects the game objects to search
309     * @param index the index
310     * @return the game object at <code>index</code>
311     */
312    @NotNull
313    private static GameObject get(@NotNull final Iterable<GameObject> gameObjects, final int index) {
314        int left = index;
315        for (final GameObject gameObject : gameObjects) {
316            if (left == 0) {
317                return gameObject;
318            }
319            left--;
320        }
321
322        Assert.fail("index " + index + " not found");
323        throw new AssertionError();
324    }
325
326    /**
327     * Checks some game objects for expected elevation values.
328     * @param gameObjects the game objects
329     * @param elevation the expected elevation value for the first game object
330     */
331    private static void check(@NotNull final Iterable<GameObject> gameObjects, final int... elevation) {
332        int i = 0;
333        for (final GameObject gameObject : gameObjects) {
334            final int thisElevation = gameObject.getAttributeInt(GameObject.ELEVATION);
335            final int expectedElevation = i < elevation.length ? elevation[i] : 0;
336            Assert.assertEquals(gameObject.getBestName(), expectedElevation, thisElevation);
337            i++;
338        }
339    }
340
341}