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.model.index;
021
022import java.io.File;
023import java.io.IOException;
024import java.util.Collection;
025import java.util.Iterator;
026import net.sf.gridarta.model.archetype.TestArchetype;
027import net.sf.gridarta.model.gameobject.TestGameObject;
028import net.sf.gridarta.model.maparchobject.TestMapArchObject;
029import net.sf.gridarta.model.mapcontrol.DefaultMapControl;
030import net.sf.gridarta.model.mapcontrol.TestMapControlCreator;
031import net.sf.gridarta.model.mapmanager.MapManager;
032import net.sf.gridarta.model.mapmodel.MapModel;
033import net.sf.gridarta.model.settings.ProjectSettings;
034import net.sf.gridarta.model.settings.TestProjectSettings;
035import net.sf.gridarta.utils.StringUtils;
036import org.jetbrains.annotations.NotNull;
037import org.jetbrains.annotations.Nullable;
038import org.junit.Assert;
039import org.junit.Test;
040
041/**
042 * Regression tests for {@link MapsIndexer}.
043 * @author Andreas Kirschbaum
044 */
045public class MapsIndexerTest {
046
047    /**
048     * Checks that basic indexing works as expected.
049     * @throws InterruptedException if the test fails
050     * @throws IOException if the test fails
051     */
052    @Test
053    public void test1() throws InterruptedException, IOException {
054        final ProjectSettings projectSettings = new TestProjectSettings();
055        final TestMapControlCreator mapControlCreator = new TestMapControlCreator();
056        final MapManager<TestGameObject, TestMapArchObject, TestArchetype> mapManager = mapControlCreator.newMapManager();
057        final File mapsDirectory = createMapsDirectory(mapControlCreator, projectSettings, "map1:Map1", "path/map2:Map Name2");
058        try {
059            final MapsIndex index = new MapsIndex();
060            projectSettings.setMapsDirectory(mapsDirectory);
061            final MapsIndexer<TestGameObject, TestMapArchObject, TestArchetype> indexer = new MapsIndexer<TestGameObject, TestMapArchObject, TestArchetype>(index, mapManager, projectSettings);
062            indexer.start();
063            indexer.waitForIdle();
064            indexer.stop();
065            Assert.assertEquals(2, index.findPartialName("").size());
066            assertEquals(index.findPartialName("Map1"), mapsDirectory, "map1");
067            assertEquals(index.findPartialName("Map Name2"), mapsDirectory, "path/map2");
068        } finally {
069            deleteTempDir(mapsDirectory);
070        }
071    }
072
073    /**
074     * Checks that a {@link Collection} of {@link File Files} contains exactly
075     * one expected value. Fails the test otherwise.
076     * @param mapPaths the collection of files
077     * @param mapsDirectory the maps directory
078     * @param mapPath the map path (relative to mapsDirectory) of the expected
079     * value
080     */
081    private static void assertEquals(@NotNull final Collection<File> mapPaths, @NotNull final File mapsDirectory, @NotNull final String mapPath) {
082        Assert.assertEquals(1, mapPaths.size());
083        final Iterator<File> it = mapPaths.iterator();
084        Assert.assertEquals(new File(mapsDirectory, mapPath), it.next());
085    }
086
087    /**
088     * Creates a maps directory consisting of a set of maps. Each "spec" value
089     * describes a map to create. Its format is "<map path>:<map name>", for
090     * example "path/to/map:Name of Map".
091     * @param mapControlCreator the map control creator for creating the maps
092     * @param projectSettings the project settings to use
093     * @param specs the maps to create
094     * @return the maps directory
095     * @throws IOException if the maps directory could not be created
096     */
097    @NotNull
098    private static File createMapsDirectory(@NotNull final TestMapControlCreator mapControlCreator, @NotNull final ProjectSettings projectSettings, @NotNull final String... specs) throws IOException {
099        final File mapsDirectory = createTempDir("gridarta");
100        @Nullable File directoryToDelete = mapsDirectory;
101        try {
102            for (final String spec : specs) {
103                final String[] tmp = StringUtils.PATTERN_COLON.split(spec, 2);
104                if (tmp.length != 2) {
105                    throw new IllegalArgumentException();
106                }
107
108                final File mapFile = new File(mapsDirectory, tmp[0]);
109                final String mapName = tmp[1];
110
111                if (!mapFile.getParentFile().exists() && !mapFile.getParentFile().mkdirs()) {
112                    throw new IOException("cannot create directory: " + mapFile.getParentFile());
113                }
114
115                final MapModel<TestGameObject, TestMapArchObject, TestArchetype> mapModel = mapControlCreator.getMapModelCreator().newMapModel(5, 5);
116                final DefaultMapControl<TestGameObject, TestMapArchObject, TestArchetype> mapControl = new DefaultMapControl<TestGameObject, TestMapArchObject, TestArchetype>(mapModel, false, mapControlCreator.getMapWriter(), projectSettings);
117                mapControl.getMapModel().getMapArchObject().setMapName(mapName);
118                mapControl.saveAs(mapFile);
119            }
120            directoryToDelete = null;
121        } finally {
122            if (directoryToDelete != null) {
123                deleteTempDir(directoryToDelete);
124            }
125        }
126        return mapsDirectory;
127    }
128
129    /**
130     * Creates an empty directory in the default temporary directory using the
131     * given prefix.
132     * @param prefix the prefix string to be used in generating the directory's
133     * name; must be at least three characters long.
134     * @return a newly-created empty directory
135     * @throws IOException if no directory could be created
136     */
137    @NotNull
138    private static File createTempDir(@NotNull final String prefix) throws IOException {
139        final String tmpDir = System.getProperty("java.io.tmpdir");
140        if (tmpDir == null) {
141            throw new IOException("the system property 'java.io.tmpdir' does not exist");
142        }
143
144        final File tmpFile = new File(tmpDir);
145        if (!tmpFile.exists() && !tmpFile.mkdirs()) {
146            throw new IOException("cannot create temporary directory " + tmpFile);
147        }
148
149        final File result = File.createTempFile(prefix, null);
150        if (!result.delete()) {
151            throw new IOException("cannot delete temporary file " + result);
152        }
153        if (!result.mkdir()) {
154            throw new IOException("cannot create temporary directory " + result);
155        }
156
157        return result;
158    }
159
160    /**
161     * Deletes a temporary directory.
162     * @param dir the directory
163     */
164    private static void deleteTempDir(final File dir) {
165        final File[] files = dir.listFiles();
166        if (files != null) {
167            for (final File file : files) {
168                if (file.isDirectory()) {
169                    deleteTempDir(file);
170                } else if (!file.delete()) {
171                    Assert.fail("cannot delete file " + file);
172                }
173            }
174        }
175        if (!dir.delete()) {
176            Assert.fail("cannot delete directory " + dir);
177        }
178    }
179
180}