EMMA Coverage Report (generated Sun Apr 20 22:38:01 CEST 2008)
[all classes][net.sf.jomic.tools]

COVERAGE SUMMARY FOR SOURCE FILE [TestTools.java]

nameclass, %method, %block, %line, %
TestTools.java100% (1/1)80%  (41/51)63%  (1234/1947)69%  (258.4/372)

COVERAGE BREAKDOWN BY CLASS AND METHOD

nameclass, %method, %block, %line, %
     
class TestTools100% (1/1)80%  (41/51)63%  (1234/1947)69%  (258.4/372)
assertGreaterOrEqual (double, double): void 0%   (0/1)0%   (0/21)0%   (0/2)
assertLessOrEqual (double, double): void 0%   (0/1)0%   (0/21)0%   (0/2)
assertLessThan (double, double): void 0%   (0/1)0%   (0/21)0%   (0/2)
createTempDir (Class, String): File 0%   (0/1)0%   (0/17)0%   (0/2)
createTempFile (Class, String, String): File 0%   (0/1)0%   (0/29)0%   (0/5)
createTempFile (String, String): File 0%   (0/1)0%   (0/26)0%   (0/5)
createTempZipArchive (Class, String, String [], String []): File 0%   (0/1)0%   (0/13)0%   (0/3)
createTestFrame (JComponent, Class, String): JFrame 0%   (0/1)0%   (0/70)0%   (0/15)
getJomicHome (): File 0%   (0/1)0%   (0/12)0%   (0/2)
getTestsBaseDir (): File 0%   (0/1)0%   (0/3)0%   (0/1)
assertFilesEqual (String): void 100% (1/1)35%  (17/48)38%  (5/13)
createImageInputStream (File): ImageInputStream 100% (1/1)41%  (11/27)70%  (3.5/5)
setupLogging (): void 100% (1/1)46%  (38/82)49%  (10.3/21)
assertFilesEqual (File, File): void 100% (1/1)46%  (45/97)67%  (14.8/22)
getTestImage (String): RenderedImage 100% (1/1)49%  (28/57)58%  (7.5/13)
waitSomeTime (): void 100% (1/1)50%  (6/12)60%  (3/5)
getCleanTestOutputFolder (String): File 100% (1/1)56%  (18/32)71%  (5/7)
createZipArchive (File, String [], String []): void 100% (1/1)59%  (91/153)74%  (16.9/23)
TestTools (): void 100% (1/1)62%  (158/254)65%  (30.7/47)
copyTestFile (String, String): void 100% (1/1)73%  (22/30)83%  (5/6)
getTestFiles (String): File [] 100% (1/1)73%  (55/75)83%  (10/12)
createTestZipArchive (File, String [], String []): void 100% (1/1)74%  (71/96)82%  (16.4/20)
getTestFile (String): File 100% (1/1)76%  (39/51)92%  (11/12)
<static initializer> 100% (1/1)80%  (12/15)80%  (0.8/1)
getAtOrNull (String [], int): String 100% (1/1)82%  (18/22)90%  (4.5/5)
assertEquals (Dimension, Dimension): void 100% (1/1)83%  (15/18)80%  (4/5)
assertEquals (String [], String []): void 100% (1/1)85%  (45/53)88%  (7/8)
assertEquals (byte [], byte []): void 100% (1/1)85%  (45/53)88%  (7/8)
assertEquals (int [], int []): void 100% (1/1)85%  (45/53)88%  (7/8)
setupTestSettings (Class, String, String []): void 100% (1/1)89%  (97/109)94%  (19.6/21)
writeImageFile (File, RenderedImage): void 100% (1/1)89%  (42/47)97%  (9.7/10)
getTestFileName (Class, String, String, String): String 100% (1/1)92%  (48/52)94%  (8.5/9)
addZipEntry (ZipOutputStream, String, String): void 100% (1/1)93%  (69/74)96%  (16.4/17)
assertGreaterOrEqual (long, long): void 100% (1/1)95%  (20/21)98%  (2/2)
assertGreaterThan (double, double): void 100% (1/1)95%  (20/21)98%  (2/2)
assertGreaterThan (long, long): void 100% (1/1)95%  (20/21)98%  (2/2)
assertLessOrEqual (long, long): void 100% (1/1)95%  (20/21)98%  (2/2)
assertLessThan (long, long): void 100% (1/1)95%  (20/21)98%  (2/2)
getTestComicFile (): File 100% (1/1)100% (4/4)100% (1/1)
getTestExpectedFile (String): File 100% (1/1)100% (7/7)100% (1/1)
getTestGeneratedInputDir (): File 100% (1/1)100% (3/3)100% (1/1)
getTestGeneratedInputFile (String): File 100% (1/1)100% (7/7)100% (1/1)
getTestImage (): RenderedImage 100% (1/1)100% (4/4)100% (1/1)
getTestImageFile (): File 100% (1/1)100% (4/4)100% (1/1)
getTestInputFile (String): File 100% (1/1)100% (7/7)100% (1/1)
getTestOutputFile (String): File 100% (1/1)100% (7/7)100% (1/1)
getTestTextFile (): File 100% (1/1)100% (4/4)100% (1/1)
instance (): TestTools 100% (1/1)100% (8/8)100% (3/3)
lengthOr0 (Object []): int 100% (1/1)100% (10/10)100% (4/4)
setupAbbotLogging (): void 100% (1/1)100% (13/13)100% (2/2)
setupCache (): void 100% (1/1)100% (21/21)100% (7/7)

1// Jomic - a viewer for comic book archives.
2// Copyright (C) 2004-2008 Thomas Aglassinger
3//
4// This program is free software: you can redistribute it and/or modify
5// it under the terms of the GNU General Public License as published by
6// the Free Software Foundation, either version 3 of the License, or
7// (at your option) any later version.
8//
9// This program is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12// GNU General Public License for more details.
13//
14// You should have received a copy of the GNU General Public License
15// along with this program.  If not, see <http://www.gnu.org/licenses/>.
16package net.sf.jomic.tools;
17 
18import java.awt.Dimension;
19import java.awt.image.RenderedImage;
20import java.io.File;
21import java.io.FileFilter;
22import java.io.FileInputStream;
23import java.io.FileNotFoundException;
24import java.io.FileOutputStream;
25import java.io.IOException;
26import java.io.InputStream;
27import java.util.Arrays;
28import java.util.Iterator;
29import java.util.LinkedList;
30import java.util.List;
31import java.util.Properties;
32import java.util.zip.ZipEntry;
33import java.util.zip.ZipOutputStream;
34 
35import javax.imageio.ImageIO;
36import javax.imageio.ImageReader;
37import javax.imageio.ImageWriter;
38import javax.imageio.stream.ImageInputStream;
39import javax.imageio.stream.ImageOutputStream;
40import javax.media.jai.JAI;
41import javax.media.jai.PlanarImage;
42import javax.swing.JComponent;
43import javax.swing.JFrame;
44 
45import junit.framework.Assert;
46import net.sf.jomic.comic.ComicCache;
47import net.sf.jomic.common.JomicConfigurator;
48import net.sf.jomic.common.PropertyConstants;
49import net.sf.jomic.common.Settings;
50import net.sf.jomic.common.StartupTools;
51import net.sf.wraplog.Logger;
52 
53import org.apache.log4j.Level;
54 
55import abbot.Log;
56 
57/**
58 *  Utility class to simplify testing.
59 *
60 * @author    Thomas Aglassinger
61 */
62public final class TestTools
63{
64    public static final String BROKEN_IMAGE_INCOMPLETE_CBZ = "broken_image_incomplete.cbz";
65    public static final String BROKEN_NO_IMAGES_PDF = "broken_no_images.pdf";
66    public static final String DISGUISED_RAR = "disguised_rar.cbz";
67    public static final String DISGUISED_ZIP = "disguised_zip.cbr";
68    public static final int FRAME_HEIGHT = 300;
69    public static final int FRAME_WIDTH = 500;
70    public static final int HUGE_PAGE_COUNT = 150;
71    public static final String HUGO_COMIC = "huge.cbz";
72    public static final String IMAGES_WITH_WRONG_SUFFIX_COMIC = "images_with_wrong_suffix.cbz";
73    public static final String SINGLE_PAGE_COMIC = "1page.cbz";
74    public static final String TEST_COMIC_CBR = "test.cbr";
75    public static final String TEST_COMIC_CBZ = "test.cbz";
76    public static final String TEST_COMIC_FILE_NAME = TEST_COMIC_CBZ;
77    public static final String TEST_COMIC_INTERNAL_ERROR = "broken_comic_internal_zip_error.cbz";
78    public static final String TEST_COMIC_LANDSCAPE_ONLY = "test_landscape_only.cbz";
79    public static final String TEST_COMIC_PDF = "test.pdf";
80    public static final String TEST_COMIC_WITH_LOGO_TITLE = "test_with_logo_title.cbz";
81    public static final String TEST_IMAGE_1_BIT = "1-bit.png";
82    public static final String TEST_IMAGE_4_BIT = "4-bit.png";
83    public static final String TEST_IMAGE_8_BIT = "01.87a.gif";
84    public static final String TEST_IMAGE_8_BIT_GRAY = "8-bit-gray.jpg";
85    public static final String TEST_IMAGE_BROKEN_BY_CUTTING_NAME = "02-broken-image-by-cutting.png";
86    public static final String TEST_IMAGE_BROKEN_BY_FILLING_NAME = "03-broken-image-by-filling.png";
87    public static final String TEST_IMAGE_BROKEN_EMPTY_NAME = "04-broken-image-empty.png";
88    public static final String TEST_IMAGE_DISGUISED_JPG = "02-jpg.png";
89    public static final String TEST_IMAGE_DISGUISED_PNG = "01-png.jpg";
90    public static final String TEST_IMAGE_FILE_NAME = "01.png";
91    public static final String TEST_IMAGE_GIF87A = "01.87a.gif";
92    public static final String TEST_IMAGE_GIF89A = "01.89a.gif";
93    public static final String TEST_IMAGE_IBM_TIFF = "01.ibm.tiff";
94    public static final String TEST_IMAGE_JP2_NAME = "01.jp2";
95    public static final String TEST_IMAGE_JPG_NAME = "27.jpg";
96    public static final String TEST_IMAGE_LANDSCAPE_NAME = "04+05.png";
97    public static final String TEST_IMAGE_MAC_TIFF = "01.mac.tiff";
98    public static final String TEST_IMAGE_PNG_NAME = "01.png";
99    public static final String TEST_IMAGE_PORTRAIT_NAME = "01.png";
100    public static final String TEST_MORONIC_NUMBERING_CBZ = "test_moronic_numbering.cbz";
101    public static final String TEST_TEXT_NAME = "test.txt";
102    public static final String THREE_PAGE_COMIC = "3pages.cbz";
103    public static final String TWO_PAGE_COMIC = "2pages.cbz";
104 
105    private static final int BUFFER_SIZE = 4096;
106 
107    private static TestTools instance;
108 
109    private int delay;
110    private FileTools fileTools;
111    private File jomicHome;
112    private Logger logger;
113    private StringTools stringTools;
114    private File testExpectedDir;
115    private File testGeneratedInputDir;
116    private File testInputDir;
117    private File testOutputDir;
118    private File testsBaseDir;
119    private File testsDataDir;
120 
121    private TestTools() {
122        logger = Logger.getLogger(TestTools.class);
123        try {
124            setupLogging();
125        } catch (IOException error) {
126            // No point in continuing any testing with a broken logging.
127            IllegalStateException bug = new IllegalStateException("cannot setup logging");
128 
129            bug.initCause(error);
130            throw bug;
131        }
132        setupAbbotLogging();
133 
134        Settings settings = Settings.instance();
135        String propertyJomicHome = PropertyConstants.TEST_JOMIC_HOME;
136 
137        settings.setDefault(PropertyConstants.TEST_JOMIC_HOME, System.getProperty("user.home"));
138 
139        String home = settings.getProperty(propertyJomicHome);
140 
141        if (home == null) {
142            String propertyJomicHomeFull = PropertyConstants.SYSTEM_PROPERTY_PREFIX + propertyJomicHome;
143 
144            throw new IllegalStateException(
145                    "property " + propertyJomicHomeFull + " must be set"
146                    + " (for example: -D" + propertyJomicHomeFull + "=/Users/me/Programs/jomic)");
147        }
148        jomicHome = new File(home);
149        testsBaseDir = new File(jomicHome, "tests");
150        if (!testsBaseDir.exists()) {
151            String propertyJomicHomeFull = PropertyConstants.SYSTEM_PROPERTY_PREFIX + propertyJomicHome;
152 
153            throw new IllegalStateException(
154                    "folder specified by " + propertyJomicHomeFull + " must exist: " + testsBaseDir);
155        }
156        testGeneratedInputDir = new File(testsBaseDir, "generated");
157        testsDataDir = testGeneratedInputDir;
158        testInputDir = new File(testsBaseDir, "input");
159        testExpectedDir = new File(testsBaseDir, "expected");
160        testOutputDir = new File(testsBaseDir, "output");
161        delay = settings.getIntProperty(PropertyConstants.TEST_DELAY);
162        if (logger.isInfoEnabled()) {
163            logger.info("jomic.home = \"" + jomicHome + "\"");
164            logger.info("jomic.delay = " + delay + " ms");
165            logger.info("testdata = \"" + testsDataDir + "\"");
166        }
167        stringTools = StringTools.instance();
168        fileTools = FileTools.instance();
169        try {
170            fileTools.mkdirs(testGeneratedInputDir);
171            fileTools.mkdirs(testOutputDir);
172        } catch (FileNotFoundException errorToTunnel) {
173            IllegalStateException error = new IllegalStateException("cannot create test data directory");
174 
175            error.initCause(errorToTunnel);
176            throw error;
177        }
178 
179        try {
180            settings.read(settings.getSettingsFile());
181        } catch (IOException errorToTunnel) {
182            IllegalStateException error = new IllegalStateException("cannot read test settings");
183 
184            error.initCause(errorToTunnel);
185            throw error;
186        }
187    }
188 
189    /**
190     *  Setup cache for tests that need it.
191     */
192    public void setupCache()
193        throws IOException {
194        ComicCache cache = ComicCache.instance();
195        Settings settings = Settings.instance();
196        File cacheDir = settings.getCacheDir();
197 
198        cacheDir = new File(cacheDir, "tests");
199        cache.setUp(cacheDir);
200        settings.setFileProperty(PropertyConstants.CACHE_DIR, cacheDir);
201    }
202 
203    /**
204     *  Create a settings file containing <code>keyValuePairs</code> and use it as default settings
205     *  file for <code>Jomic.main()</code>.
206     *
207     * @see                    PropertyConstants#SETTINGS_DIR
208     * @see                    StartupTools#getSettingsFile(String)
209     * @see                    Jomic#main(String[])
210     * @param  testCaseClass   class of TestCase the settings are for
211     * @param  testMethodName  null or name of test method the settings are for
212     * @param  keyValuePairs   array of strings of pattern <code>[key1, value1, key2, value2, ...]</code>
213     *      specifying property keys and values the settings file should contain
214     */
215    public void setupTestSettings(Class testCaseClass, String testMethodName, String[] keyValuePairs)
216        throws IOException {
217        assert testCaseClass != null;
218        assert keyValuePairs != null;
219        assert keyValuePairs.length % 2 == 0;
220 
221        File settingsBaseDir = getTestGeneratedInputDir();
222        StartupTools startupTools = StartupTools.instance();
223        String settingsDirName = testCaseClass.getName();
224 
225        if (testMethodName != null) {
226            settingsDirName += "." + testMethodName;
227        }
228 
229        File settingsDir = new File(settingsBaseDir, settingsDirName);
230 
231        System.setProperty(PropertyConstants.SYSTEM_PROPERTY_PREFIX + PropertyConstants.SETTINGS_DIR,
232                settingsDir.getAbsolutePath());
233 
234        Properties defaultSettings = new Properties();
235 
236        for (int i = 0; i < keyValuePairs.length; i += 2) {
237            String key = keyValuePairs[i];
238            String value = keyValuePairs[i + 1];
239 
240            defaultSettings.setProperty(key, value);
241        }
242 
243        Settings settings = new Settings(defaultSettings);
244 
245        fileTools.mkdirs(settingsDir);
246 
247        File settingsFile = startupTools.getSettingsFile("jomic");
248 
249        logger.info("using settings in \"{}\"", settingsFile);
250        settings.write(settingsFile);
251    }
252 
253    private void setupAbbotLogging() {
254        Log.init(new String[]{"--debug", "all"});
255    }
256 
257    /**
258     *  Attempt to read logger settings from file. If the file does not exist, use internal
259     *  defaults.
260     */
261    private void setupLogging()
262        throws IOException {
263        File loggerSettingsFile = new File("settings", "jomic-tests-logging.properties");
264        Properties loggerProperties = new Properties();
265        InputStream loggerSettingsStream = null;
266        boolean readFromFile = false;
267        org.apache.log4j.Logger root = org.apache.log4j.Logger.getRootLogger();
268 
269        root.setLevel(Level.INFO);
270        try {
271            loggerSettingsStream = new FileInputStream(loggerSettingsFile);
272            loggerProperties.load(loggerSettingsStream);
273            readFromFile = true;
274        } catch (FileNotFoundException error) {
275            loggerProperties.clear();
276            loggerProperties.setProperty("log4j.rootLogger", "INFO, stdout");
277            loggerProperties.setProperty("log4j.appender.stdout", "org.apache.log4j.ConsoleAppender");
278        } finally {
279            if (loggerSettingsStream != null) {
280                loggerSettingsStream.close();
281            }
282        }
283        JomicConfigurator.configure();
284        JomicConfigurator.setLevel(loggerProperties);
285        if (!readFromFile) {
286            if (logger.isInfoEnabled()) {
287                logger.info("cannot find logger settings \"" + loggerSettingsFile
288                        + "\"; using internal defaults");
289            }
290        }
291    }
292 
293    /**
294     *  Get a folder where test output can be written to. The folder is created and all possibly
295     *  existing files in it are removed.
296     */
297    public File getCleanTestOutputFolder(String name) {
298        File result = getTestOutputFile(name);
299 
300        fileTools.attemptToDeleteAll(result, logger);
301        try {
302            fileTools.mkdirs(result);
303        } catch (FileNotFoundException error) {
304            throw new TunneledIOException("cannot create clean test output folder: " + result, error);
305        }
306        return result;
307    }
308 
309    /**
310     *  Gets the directory where the local copy of the Jomic CVS is located. In order for this to
311     *  work, you have to set the Java property jomic.home to point to this directory.
312     */
313    public File getJomicHome() {
314        assert jomicHome != null;
315        return jomicHome;
316    }
317 
318    /**
319     *  Gets a file containing a genric test comic archive with a few images.
320     */
321    public File getTestComicFile() {
322        return getTestGeneratedInputFile(TEST_COMIC_FILE_NAME);
323    }
324 
325    /**
326     *  Get a test input file from the testdata directory.
327     */
328    public File getTestExpectedFile(String name) {
329        return new File(testExpectedDir, name);
330    }
331 
332    /**
333     *  Get existing test input file from either "tests/generated" or "tests/input".
334     *
335     * @see    #getTestGeneratedInputFile(String)
336     * @see    #getTestInputFile(String)
337     */
338    public File getTestFile(String name) {
339        File result;
340        File generatedFile = getTestGeneratedInputFile(name);
341        boolean generatedExists = generatedFile.exists();
342        File inputFile = getTestInputFile(name);
343        boolean inputExists = inputFile.exists();
344 
345        if (generatedExists) {
346            if (inputExists) {
347                throw new IllegalStateException("test file must not exist both in \"generated\" and \"input\": "
348                        + name);
349            }
350            result = generatedFile;
351        } else {
352            if (!inputExists) {
353                throw new IllegalStateException("test file must exist either in \"generated\" or \"input\": " + name);
354            }
355            result = inputFile;
356        }
357 
358        return result;
359    }
360 
361    /**
362     *  Get a plain file name for a test file. This does not yield a complete path, use <code>getTest*File()</code>
363     *  to access or store an actual test file.
364     *
365     * @see                    #getTestExpectedFile(String)
366     * @see                    #getTestInputFile(String)
367     * @see                    #getTestOutputFile(String)
368     * @param  testCaseClass   the class where the test case resides that uses the file
369     * @param  testMethodName  null or the name of the method that uses the file
370     * @param  name            null or a short name further describing the file (if the test method
371     *      needs more than one file)
372     * @param  suffix          null or file suffix without dot, for example "png"
373     */
374    public String getTestFileName(Class testCaseClass, String testMethodName, String name, String suffix) {
375        assert testCaseClass != null;
376        String result = testCaseClass.getName();
377 
378        if (testMethodName != null) {
379            result += "." + testMethodName;
380        }
381        if (name != null) {
382            result += "-" + name;
383        }
384        if (suffix != null) {
385            result += "." + suffix;
386        }
387        return result;
388    }
389 
390    /**
391     *  Get files from generated and static test data directory matching a certain pattern.
392     *
393     * @param  pattern  a regular expression describing the names of the files to get
394     */
395    public File[] getTestFiles(String pattern) {
396        List result = new LinkedList();
397        File[] testDirs = new File[]{testGeneratedInputDir, testInputDir};
398        FileFilter filter = new RegExFileFilter(pattern);
399 
400        for (int i = 0; i < testDirs.length; i += 1) {
401            File testDir = testDirs[i];
402            File[] filesToAppend = testDir.listFiles(filter);
403 
404            if (filesToAppend != null) {
405                result.addAll(Arrays.asList(filesToAppend));
406            }
407        }
408 
409        if (result.size() == 0) {
410            String message = "test directories must contain at least one file matching \""
411                    + pattern + "\": " + StringTools.instance().arrayToString(testDirs);
412 
413            throw new IllegalStateException(message);
414        }
415        return (File[]) result.toArray(new File[0]);
416    }
417 
418    /**
419     *  Get the directory where all the test data are stored.
420     */
421    public File getTestGeneratedInputDir() {
422        return testsDataDir;
423    }
424 
425    /**
426     *  Get a generated test input file from the test data directory.
427     */
428    public File getTestGeneratedInputFile(String name) {
429        return new File(testGeneratedInputDir, name);
430    }
431 
432    /**
433     *  Get the test image with the specified <code>fileName</code>.
434     */
435    public RenderedImage getTestImage(String fileName)
436        throws IOException {
437        assert fileName != null;
438        RenderedImage result;
439        File imageFile = getTestFile(fileName);
440        ImageInputStream in = createImageInputStream(imageFile);
441        ImageReader reader = (ImageReader) ImageIO.getImageReaders(in).next();
442 
443        reader.setInput(in);
444        try {
445            result = PlanarImage.wrapRenderedImage(reader.read(0));
446        } catch (Exception error) {
447            logger.warn("cannot read image using ImageIO; reverting to JAI", error);
448            result = JAI.create("fileload", imageFile.getAbsolutePath());
449            if (result == null) {
450                throw new IOException("cannot read image file: " + imageFile);
451            }
452        }
453        return result;
454    }
455 
456    /**
457     *  Get a genric test image representing some dummy comic page.
458     */
459    public RenderedImage getTestImage()
460        throws IOException {
461        return getTestImage(TEST_IMAGE_FILE_NAME);
462    }
463 
464    /**
465     *  Get a file containing a genric test image representing some dummy comic page.
466     */
467    public File getTestImageFile() {
468        return getTestFile(TEST_IMAGE_FILE_NAME);
469    }
470 
471    /**
472     *  Get a test input file from the test data directory.
473     */
474    public File getTestInputFile(String name) {
475        return new File(testInputDir, name);
476    }
477 
478    /**
479     *  Get a test input file from the test data directory.
480     */
481    public File getTestOutputFile(String name) {
482        return new File(testOutputDir, name);
483    }
484 
485    /**
486     *  Get a file containing a genric test text.
487     */
488    public File getTestTextFile() {
489        return getTestFile(TEST_TEXT_NAME);
490    }
491 
492    /**
493     *  Get the base directory where the test source code and stuff is located, typically
494     *  "${build.dir}/tests".
495     */
496    public File getTestsBaseDir() {
497        return testsBaseDir;
498    }
499 
500    /**
501     *  Get <code>data[i]</code> or null in case <code>data</code> is null or smaller than <code>index</code>
502     *  .
503     */
504    private String getAtOrNull(String[] data, int index) {
505        assert index >= 0;
506        String result = null;
507 
508        if ((data != null) && (index < data.length)) {
509            result = data[index];
510        }
511        return result;
512    }
513 
514    /**
515     *  Get accessor.
516     */
517    public static synchronized TestTools instance() {
518        if (instance == null) {
519            instance = new TestTools();
520        }
521        return instance;
522    }
523 
524    public void assertEquals(byte[] expected, byte[] actual) {
525        assert expected != null;
526        assert actual != null;
527        int expectedCount = expected.length;
528        int actualCount = actual.length;
529 
530        for (int i = 0; i < Math.min(expectedCount, actualCount); i += 1) {
531            Assert.assertEquals("data at index " + i + " must be equal", expected[i], actual[i]);
532        }
533        Assert.assertEquals("array length must be equal", expectedCount, actualCount);
534    }
535 
536    public void assertEquals(int[] expected, int[] actual) {
537        assert expected != null;
538        assert actual != null;
539        int expectedCount = expected.length;
540        int actualCount = actual.length;
541 
542        for (int i = 0; i < Math.min(expectedCount, actualCount); i += 1) {
543            Assert.assertEquals("data at index " + i + " must be equal", expected[i], actual[i]);
544        }
545        Assert.assertEquals("array length must be equal", expectedCount, actualCount);
546    }
547 
548    public void assertEquals(String[] expected, String[] actual) {
549        assert expected != null;
550        assert actual != null;
551        int expectedCount = expected.length;
552        int actualCount = actual.length;
553 
554        for (int i = 0; i < Math.min(expectedCount, actualCount); i += 1) {
555            Assert.assertEquals("data at index " + i + " must be equal", expected[i], actual[i]);
556        }
557        Assert.assertEquals("array length must be equal", expectedCount, actualCount);
558    }
559 
560    public void assertEquals(Dimension expected, Dimension actual) {
561        if ((expected == null) || (actual == null)) {
562            Assert.assertEquals(expected, actual);
563        }
564        Assert.assertEquals(expected.width, actual.width);
565        Assert.assertEquals(expected.height, actual.height);
566    }
567 
568    public void assertFilesEqual(String baseName) {
569        File expectedFile = getTestExpectedFile(baseName);
570        File outputFile = getTestOutputFile(baseName);
571 
572        if (expectedFile.exists()) {
573            assertFilesEqual(expectedFile, outputFile);
574        } else {
575            logger.warn("cannot find expected file, creating it: " + expectedFile);
576            try {
577                fileTools.copyFile(outputFile, expectedFile);
578            } catch (IOException error) {
579                String errorMessage = "cannot create expected file";
580                IllegalStateException tunneledError = new IllegalStateException(errorMessage);
581 
582                tunneledError.initCause(error);
583                throw tunneledError;
584            }
585        }
586    }
587 
588    public void assertFilesEqual(File expectedFile, File actualFile) {
589        // TODO: Improve performance by changing read() to read(buffer).
590        // TODO: Improve error message by including hex dump of a few characters surrounding the mismatch.
591        try {
592            InputStream expectedStream = new FileInputStream(expectedFile);
593 
594            try {
595                InputStream actualStream = new FileInputStream(actualFile);
596                long filePosition = 0;
597 
598                try {
599                    int expectedChar = 0;
600                    int actualChar = 0;
601 
602                    while ((expectedChar == actualChar) && (expectedChar >= 0) && (actualChar >= 0)) {
603                        expectedChar = expectedStream.read();
604                        actualChar = actualStream.read();
605                        if (expectedChar != actualChar) {
606                            // We are doing this inside an "if" so the message only has to be
607                            // computed in case anythings wrong. This improves performance.
608                            String message = "character at postion " + filePosition + " in " + expectedFile
609                                    + " must match " + actualFile;
610 
611                            Assert.assertEquals(message, expectedChar, actualChar);
612                        } else {
613                            filePosition += 1;
614                        }
615                    }
616                } finally {
617                    actualStream.close();
618                }
619            } finally {
620                expectedStream.close();
621            }
622        } catch (IOException error) {
623            String errorMessage = "cannot compare files " + expectedFile + " and " + actualFile;
624 
625            throw new TunneledIOException(errorMessage, error);
626        }
627    }
628 
629    public void assertGreaterOrEqual(double actual, double limit) {
630        Assert.assertTrue("" + actual + " >= " + limit, actual >= limit);
631    }
632 
633    public void assertGreaterOrEqual(long actual, long limit) {
634        Assert.assertTrue("" + actual + " >= " + limit, actual >= limit);
635    }
636 
637    public void assertGreaterThan(double actual, double limit) {
638        Assert.assertTrue("" + actual + " > " + limit, actual > limit);
639    }
640 
641    public void assertGreaterThan(long actual, long limit) {
642        Assert.assertTrue("" + actual + " > " + limit, actual > limit);
643    }
644 
645    public void assertLessOrEqual(double actual, double limit) {
646        Assert.assertTrue("" + actual + " <= " + limit, actual <= limit);
647    }
648 
649    public void assertLessOrEqual(long actual, long limit) {
650        Assert.assertTrue("" + actual + " <= " + limit, actual <= limit);
651    }
652 
653    public void assertLessThan(double actual, double limit) {
654        Assert.assertTrue("" + actual + " < " + limit, actual < limit);
655    }
656 
657    public void assertLessThan(long actual, long limit) {
658        Assert.assertTrue("" + actual + " < " + limit, actual < limit);
659    }
660 
661    public void copyTestFile(String sourceName, String targetName)
662        throws IOException {
663        assert sourceName != null;
664        assert targetName != null;
665        File source = getTestFile(sourceName);
666        File target = getTestGeneratedInputFile(targetName);
667 
668        fileTools.copyFile(source, target);
669    }
670 
671    /**
672     *  Same as ImageIO.createImageInputStream, but throws a <code>FileNotFoundException</code> if
673     *  <code>imageFile</code> cannot be found (instead of returning <code>null</code>). Why the
674     *  original does not work that way already is beyond me.
675     */
676    public ImageInputStream createImageInputStream(File imageFile)
677        throws IOException {
678        assert imageFile != null;
679        ImageInputStream result = ImageIO.createImageInputStream(imageFile);
680 
681        if (result == null) {
682            throw new FileNotFoundException("cannot find image file: " + imageFile);
683        }
684        return result;
685    }
686 
687    /**
688     *  Create a temporary test directory.
689     */
690    public File createTempDir(Class clazz, String prefix)
691        throws IOException {
692        File result = fileTools.createTempDir(clazz.getName() + "-" + prefix);
693 
694        // TODO: automatically remove directory when done.
695        return result;
696    }
697 
698    /**
699     *  Create a temporary file that will be deleted on exit unless the system property
700     *  net.sf.jomic.test.keepTempFiles has been set to <code>true</code>.
701     *
702     * @see    File#createTempFile(java.lang.String, java.lang.String)
703     * @see    File#deleteOnExit()
704     */
705    public File createTempFile(String prefix, String suffix)
706        throws IOException {
707        File result = File.createTempFile(prefix, suffix);
708 
709        if (Boolean.getBoolean(PropertyConstants.TEST_KEEP_TEMP_FILES)) {
710            logger.warn("keeping temp file: " + StringTools.instance().sourced(result.getAbsolutePath()));
711        } else {
712            result.deleteOnExit();
713        }
714        return result;
715    }
716 
717    /**
718     *  Create a temporary file that will be deleted on exit unless the system property
719     *  net.sf.jomic.test.keepTempFiles has been set to <code>true</code>. The name of the file is
720     *  prefixed by the name of <code>claszz</code> and <code>prefix</code>, separated by a hyphen
721     *  (-) provided <code>prefix</code> is not <code>null</code>.
722     *
723     * @see    File#createTempFile(java.lang.String, java.lang.String)
724     * @see    File#deleteOnExit()
725     */
726    public File createTempFile(Class clazz, String prefix, String suffix)
727        throws IOException {
728        assert clazz != null;
729        String actualPrefix = clazz.getName();
730 
731        if (prefix != null) {
732            actualPrefix += "-" + prefix;
733        }
734        return createTempFile(actualPrefix, suffix);
735    }
736 
737    /**
738     *  Create a temporary ZIP archive with a file name derived from <code>caller</code> and <code>baseName</code>
739     *  . For <code>inNames</code> and <code>outNames</code> the same things apply as with <code>createTestZipArchive()</code>
740     *  .
741     *
742     * @see    #createTempFile(Class, String, String)
743     * @see    #createTestZipArchive(File, String[], String[])
744     */
745    public File createTempZipArchive(Class caller, String baseName, String[] inNames,
746            String[] outNames)
747        throws IOException {
748        File result = createTempFile(caller, baseName, ".cbz");
749 
750        createTestZipArchive(result, inNames, outNames);
751        return result;
752    }
753 
754    /**
755     *  Create and show a test frame.
756     *
757     * @param  component  the JComponent to show inside the frame
758     * @param  test       the class of the TestCase opening the frame; to be shown as title
759     * @param  method     the method in the TestCase opening the frame, or <code>null</code> if none
760     *      needed to be shown in the title
761     */
762    public JFrame createTestFrame(JComponent component, Class test, String method) {
763        assert test != null;
764        assert component != null;
765        String title = test.getClass().getName();
766 
767        if (method != null) {
768            title += "." + method;
769        }
770        JFrame result = new JFrame(title);
771        boolean ok = false;
772 
773        try {
774            result.getContentPane().add(component);
775            result.setSize(FRAME_WIDTH, FRAME_HEIGHT);
776            result.pack();
777            result.setVisible(true);
778            ok = true;
779        } finally {
780            if (!ok) {
781                result.dispose();
782            }
783        }
784        return result;
785    }
786 
787    /**
788     *  Create a test ZIP archive in <code>zipFile</code>. One of <code>inNames</code> or <code>outNames</code>
789     *  can be null or shorter than the other, in which case the missing entries will be filled with
790     *  names derived from the other names.
791     *
792     * @see              #getTestFile(String)
793     * @param  inNames   relative input file names that will be expaned to full paths using <code>getTestFile()</code>
794     * @param  outNames  file names to be used in archive (with path); missing names will be filled
795     *      with the plain file name (without path) derived from the corresponding entry in <code>inNames</code>
796     *      .
797     */
798    public void createTestZipArchive(File zipFile, String[] inNames,
799            String[] outNames)
800        throws IOException {
801        assert !((inNames == null) && (outNames == null));
802        int inLength = lengthOr0(inNames);
803        int outLength = lengthOr0(outNames);
804 
805        int nameCount = Math.max(inLength, outLength);
806        String[] filledInNames = new String[nameCount];
807        String[] filledOutNames = new String[nameCount];
808 
809        for (int i = 0; i < nameCount; i += 1) {
810            String inName = getAtOrNull(inNames, i);
811            String outName = getAtOrNull(outNames, i);
812 
813            if (inName == null) {
814                assert outName != null;
815                inName = outName;
816            } else if (outName == null) {
817                outName = inName;
818            } else {
819                assert inName != null;
820                assert outName != null;
821            }
822            filledInNames[i] = getTestFile(inName).getAbsolutePath();
823            filledOutNames[i] = outName;
824        }
825 
826        createZipArchive(zipFile, filledInNames, filledOutNames);
827    }
828 
829    public void createZipArchive(File zipFile, String[] inNames,
830            String[] outNames)
831        throws IOException {
832        assert zipFile != null;
833        assert inNames != null;
834        assert inNames.length > 0;
835        assert outNames != null;
836        assert inNames.length == outNames.length :
837                "outNames.length must " + inNames.length + " but is " + outNames.length;
838        boolean done = false;
839 
840        if (logger.isInfoEnabled()) {
841            logger.info("create zip archive: " + zipFile);
842        }
843        ZipOutputStream out = new ZipOutputStream(new FileOutputStream(zipFile));
844 
845        try {
846            for (int i = 0; i < inNames.length; i += 1) {
847                String inName = inNames[i];
848                String outName = null;
849 
850                assert inName != null;
851                if ((outNames != null) && (outNames.length > i)) {
852                    outName = outNames[i];
853                }
854                if (outName == null) {
855                    outName = inName;
856                }
857                addZipEntry(out, inName, outName);
858                done = true;
859            }
860        } finally {
861            out.close();
862            if (!done) {
863                // Delete incomplete archive.
864                fileTools.deleteOrWarn(zipFile, logger);
865            }
866        }
867    }
868 
869    /**
870     *  Waits some time. The exact time can be specified in the property PROPERTY_JOMIC_DELAY. If
871     *  this is missing, use an internal default value.
872     */
873    public void waitSomeTime() {
874        try {
875            Thread.sleep(delay);
876        } catch (InterruptedException interruption) {
877            logger.warn("interrupted", interruption);
878        }
879    }
880 
881    public void writeImageFile(File targetImageFile, RenderedImage imageToWrite)
882        throws IOException {
883        Iterator writers = ImageIO.getImageWritersByFormatName(fileTools.getSuffix(targetImageFile));
884        ImageWriter writer = (ImageWriter) writers.next();
885 
886        if (logger.isInfoEnabled()) {
887            logger.info("write test image " + stringTools.sourced(targetImageFile.getAbsolutePath()));
888        }
889        ImageOutputStream ios = ImageIO.createImageOutputStream(targetImageFile);
890 
891        try {
892            writer.setOutput(ios);
893            writer.write(imageToWrite);
894        } finally {
895            ios.close();
896        }
897    }
898 
899    private void addZipEntry(ZipOutputStream out, String inName, String outName)
900        throws IOException {
901        byte[] buffer = new byte[BUFFER_SIZE];
902        ZipEntry zipEntry = new ZipEntry(outName);
903 
904        if (logger.isDebugEnabled()) {
905            logger.debug("add " + stringTools.sourced(inName) + " + "
906                    + stringTools.sourced(outName));
907        }
908 
909        out.putNextEntry(zipEntry);
910 
911        FileInputStream in = new FileInputStream(inName);
912        boolean continueReading = true;
913 
914        try {
915            while (continueReading) {
916                int bytesRead = in.read(buffer);
917 
918                continueReading = (bytesRead > 0);
919                if (continueReading) {
920                    out.write(buffer, 0, bytesRead);
921                }
922            }
923        } finally {
924            in.close();
925        }
926        out.closeEntry();
927    }
928 
929    private int lengthOr0(Object[] some) {
930        int result;
931 
932        if (some == null) {
933            result = 0;
934        } else {
935            result = some.length;
936        }
937        return result;
938    }
939}

[all classes][net.sf.jomic.tools]
EMMA 2.0.4217 (C) Vladimir Roubtsov