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.resource;
021
022import java.io.BufferedWriter;
023import java.io.File;
024import java.io.FileOutputStream;
025import java.io.IOException;
026import java.io.OutputStream;
027import java.io.OutputStreamWriter;
028import java.io.Writer;
029import java.util.ArrayList;
030import java.util.Collections;
031import java.util.Enumeration;
032import java.util.HashMap;
033import java.util.List;
034import java.util.Map;
035import java.util.ResourceBundle;
036import java.util.regex.Pattern;
037import net.sf.gridarta.model.anim.AnimationObject;
038import net.sf.gridarta.model.anim.AnimationObjects;
039import net.sf.gridarta.model.anim.TestAnimationObjects;
040import net.sf.gridarta.model.archetype.ArchetypeFactory;
041import net.sf.gridarta.model.archetype.TestArchetype;
042import net.sf.gridarta.model.archetype.TestArchetypeBuilder;
043import net.sf.gridarta.model.archetype.TestArchetypeFactory;
044import net.sf.gridarta.model.archetypeset.ArchetypeSet;
045import net.sf.gridarta.model.archetypeset.DefaultArchetypeSet;
046import net.sf.gridarta.model.errorview.ErrorView;
047import net.sf.gridarta.model.errorview.TestErrorView;
048import net.sf.gridarta.model.face.ArchFaceProvider;
049import net.sf.gridarta.model.face.FaceObjectProviders;
050import net.sf.gridarta.model.face.FaceObjects;
051import net.sf.gridarta.model.face.TestFaceObjects;
052import net.sf.gridarta.model.gameobject.GameObjectFactory;
053import net.sf.gridarta.model.gameobject.TestGameObject;
054import net.sf.gridarta.model.gameobject.TestGameObjectFactory;
055import net.sf.gridarta.model.io.AbstractArchetypeParser;
056import net.sf.gridarta.model.io.TestArchetypeParser;
057import net.sf.gridarta.model.maparchobject.TestMapArchObject;
058import net.sf.gridarta.utils.ResourceIcons;
059import net.sf.japi.swing.action.ActionBuilder;
060import net.sf.japi.swing.action.ActionBuilderFactory;
061import net.sf.japi.swing.action.DefaultActionBuilder;
062import net.sf.japi.util.IteratorEnumeration;
063import org.jetbrains.annotations.NotNull;
064import org.jetbrains.annotations.Nullable;
065import org.junit.Assert;
066import org.junit.Test;
067
068/**
069 * Regression tests for {@link AbstractFilesResourcesReader}.
070 * @author Andreas Kirschbaum
071 */
072public class AbstractFilesResourcesReaderTest {
073
074    /**
075     * The {@link Pattern} for matching validator keys for default values.
076     */
077    @NotNull
078    private static final Pattern PATTERN_DEFAULT_KEY = Pattern.compile("fileDialog\\.filter\\..*");
079
080    /**
081     * checks that animations read from .anim files have correct path names.
082     * @throws IOException if the test fails
083     */
084    @Test
085    public void testAnimationPaths() throws IOException {
086        final File tmpDirectory = File.createTempFile("gridarta", null);
087        try {
088            Assert.assertTrue(tmpDirectory.delete());
089            Assert.assertTrue(tmpDirectory.mkdir());
090            final File archDirectory = new File(tmpDirectory, "archetypes");
091            Assert.assertTrue(archDirectory.mkdir());
092            final File collectedDirectory = new File(tmpDirectory, "collected");
093            Assert.assertTrue(collectedDirectory.mkdir());
094            createAnimationFile(archDirectory, "anim1");
095            createAnimationFile(new File(archDirectory, "p"), "anim2");
096            createAnimationFile(new File(new File(new File(archDirectory, "p"), "q"), "r"), "anim3");
097
098            final ActionBuilder actionBuilder = new DefaultActionBuilder("net.sf.gridarta");
099            ActionBuilderFactory.getInstance().putActionBuilder("net.sf.gridarta", actionBuilder);
100            final ResourceBundle resourceBundle = new ResourceBundle() {
101
102                /**
103                 * Maps key to associated object.
104                 */
105                @NotNull
106                private final Map<String, Object> objects = new HashMap<String, Object>();
107
108                @Nullable
109                @Override
110                protected Object handleGetObject(@NotNull final String key) {
111                    final Object existingObject = objects.get(key);
112                    if (existingObject != null) {
113                        return existingObject;
114                    }
115
116                    final Object object;
117                    if (PATTERN_DEFAULT_KEY.matcher(key).matches()) {
118                        object = "Description";
119                    } else {
120                        return null;
121                    }
122                    objects.put(key, object);
123                    return object;
124                }
125
126                @NotNull
127                @Override
128                public Enumeration<String> getKeys() {
129                    return new IteratorEnumeration<String>(Collections.unmodifiableSet(objects.keySet()).iterator());
130                }
131
132            };
133            actionBuilder.addBundle(resourceBundle);
134
135            final AnimationObjects animationObjects = readAnimations(archDirectory, collectedDirectory);
136
137            Assert.assertEquals(3, animationObjects.size());
138            final AnimationObject anim1 = animationObjects.get("anim1");
139            final AnimationObject anim2 = animationObjects.get("anim2");
140            final AnimationObject anim3 = animationObjects.get("anim3");
141            Assert.assertNotNull(anim1);
142            Assert.assertNotNull(anim2);
143            Assert.assertNotNull(anim3);
144            Assert.assertEquals("anim1", anim1.getAnimName());
145            Assert.assertEquals("anim2", anim2.getAnimName());
146            Assert.assertEquals("anim3", anim3.getAnimName());
147            Assert.assertEquals("/anim1", anim1.getPath());
148            Assert.assertEquals("/p/anim2", anim2.getPath());
149            Assert.assertEquals("/p/q/r/anim3", anim3.getPath());
150        } finally {
151            delete(tmpDirectory);
152        }
153    }
154
155    /**
156     * Reads resources from individual files.
157     * @param archDirectory the arch directory
158     * @param collectedDirectory the collected directory
159     * @return the animation objects instance
160     */
161    @NotNull
162    private static AnimationObjects readAnimations(@NotNull final File archDirectory, @NotNull final File collectedDirectory) {
163        final ArchFaceProvider archFaceProvider = new ArchFaceProvider();
164        final FaceObjects faceObjects = new TestFaceObjects();
165        final ResourceIcons resourceIcons = new ResourceIcons();
166        final FaceObjectProviders faceObjectProviders = new FaceObjectProviders(1, faceObjects, resourceIcons);
167        final AnimationObjects animationObjects = new TestAnimationObjects();
168        final ArchetypeFactory<TestGameObject, TestMapArchObject, TestArchetype> archetypeFactory = new TestArchetypeFactory(faceObjectProviders, animationObjects);
169        final ArchetypeSet<TestGameObject, TestMapArchObject, TestArchetype> archetypeSet = new DefaultArchetypeSet<TestGameObject, TestMapArchObject, TestArchetype>(archetypeFactory, null);
170        final GameObjectFactory<TestGameObject, TestMapArchObject, TestArchetype> gameObjectFactory = new TestGameObjectFactory(faceObjectProviders, animationObjects);
171        final TestArchetypeBuilder archetypeBuilder = new TestArchetypeBuilder(gameObjectFactory);
172        final AbstractArchetypeParser<TestGameObject, TestMapArchObject, TestArchetype, ?> archetypeParser = new TestArchetypeParser(archetypeBuilder, animationObjects, archetypeSet);
173        final AbstractResourcesReader<TestGameObject> filesResourcesReader = new TestFilesResourcesReader(archDirectory, archetypeSet, archetypeParser, archFaceProvider, collectedDirectory, null, animationObjects, faceObjects);
174        final List<TestGameObject> invObjects = new ArrayList<TestGameObject>();
175        final ErrorView errorView = new TestErrorView();
176        filesResourcesReader.read(errorView, invObjects);
177        return animationObjects;
178    }
179
180    /**
181     * Creates a new .anim file.
182     * @param directory the directory to create the file in; will be created if
183     * it does not yet exist
184     * @param animName the name of the animation
185     * @throws IOException if an I/O error occurs
186     */
187    private static void createAnimationFile(@NotNull final File directory, @NotNull final String animName) throws IOException {
188        if (!directory.isDirectory()) {
189            Assert.assertTrue(directory.mkdirs());
190        }
191
192        final File file = new File(directory, animName + ".anim");
193        Assert.assertFalse(file.exists());
194        final OutputStream fileOutputStream = new FileOutputStream(file);
195        try {
196            final Writer outputStreamWriter = new OutputStreamWriter(fileOutputStream, "UTF-8");
197            try {
198                final Writer bufferedWriter = new BufferedWriter(outputStreamWriter);
199                try {
200                    bufferedWriter.append("anim ").append(animName).append("\n");
201                    bufferedWriter.append("face1\n");
202                    bufferedWriter.append("face2\n");
203                    bufferedWriter.append("mina\n");
204                } finally {
205                    bufferedWriter.close();
206                }
207            } finally {
208                outputStreamWriter.close();
209            }
210        } finally {
211            fileOutputStream.close();
212        }
213    }
214
215    /**
216     * Recursively deletes a directory.
217     * @param file the file or directory to delete
218     */
219    private static void delete(@NotNull final File file) {
220        //noinspection ResultOfMethodCallIgnored
221        file.delete();
222
223        if (file.isDirectory()) {
224            final File[] files = file.listFiles();
225            if (files != null) {
226                for (final File subFile : files) {
227                    delete(subFile);
228                }
229            }
230        }
231
232        if (file.exists()) {
233            Assert.assertTrue(file.delete());
234        }
235    }
236
237}