001    /*--------------------------------------------------------------------------+
002    $Id: TestDataManager.java 26268 2010-02-18 10:44:30Z juergens $
003    |                                                                          |
004    | Copyright 2005-2010 Technische Universitaet Muenchen                     |
005    |                                                                          |
006    | Licensed under the Apache License, Version 2.0 (the "License");          |
007    | you may not use this file except in compliance with the License.         |
008    | You may obtain a copy of the License at                                  |
009    |                                                                          |
010    |    http://www.apache.org/licenses/LICENSE-2.0                            |
011    |                                                                          |
012    | Unless required by applicable law or agreed to in writing, software      |
013    | distributed under the License is distributed on an "AS IS" BASIS,        |
014    | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
015    | See the License for the specific language governing permissions and      |
016    | limitations under the License.                                           |
017    +--------------------------------------------------------------------------*/
018    package edu.tum.cs.commons.test;
019    
020    import java.io.File;
021    import java.io.FileWriter;
022    import java.io.IOException;
023    import java.io.PrintWriter;
024    import java.util.ArrayList;
025    import java.util.Collections;
026    import java.util.HashMap;
027    import java.util.HashSet;
028    import java.util.Map;
029    
030    import junit.framework.TestCase;
031    import edu.tum.cs.commons.collections.TwoDimHashMap;
032    import edu.tum.cs.commons.filesystem.FileSystemUtils;
033    
034    /**
035     * Support class for identifying unused test data files. This class provides a
036     * method to access test data files and logs which test cases access which test
037     * files. On every access to a file, access statistic for used and unused files
038     * are written to {@value #REPORT_DIRECTORY_NAME}.
039     * <p>
040     * This class is best used via inheriting from {@link CCSMTestCaseBase}.
041     * 
042     * @author Florian Deissenboeck
043     * @author Benjamin Hummel
044     * @author $Author: juergens $
045     * @version $Rev: 26268 $
046     * @levd.rating GREEN Hash: 4E808795FAB1BE3BBDA0729E21312104
047     */
048    public class TestDataManager {
049    
050            /** Name of the directory to write reports to. */
051            public static final String REPORT_DIRECTORY_NAME = "test-tmp";
052    
053            /** Map of all instances (which is indexed by managed directory). */
054            private static Map<File, TestDataManager> instances = new HashMap<File, TestDataManager>();
055    
056            /** Returns the instance of the test data manager for the given directory. */
057            public static TestDataManager getInstance(File directory) {
058                    if (!instances.containsKey(directory)) {
059                            instances.put(directory, new TestDataManager(directory));
060                    }
061                    return instances.get(directory);
062            }
063    
064            /** The set of unused files. */
065            private final HashSet<String> unusedFiles = new HashSet<String>();
066    
067            /** Storage for all test files used so far. */
068            private final TwoDimHashMap<Class<?>, TestCase, HashSet<String>> usedFiles = new TwoDimHashMap<Class<?>, TestCase, HashSet<String>>();
069    
070            /** The directory this manager works in. */
071            private final File directory;
072    
073            /** Private constructor. */
074            private TestDataManager(File directory) {
075                    this.directory = directory;
076    
077                    if (!directory.exists() || !directory.isDirectory()) {
078                            return;
079                    }
080    
081                    for (File file : directory.listFiles()) {
082                            if (file.isFile()) {
083                                    unusedFiles.add(file.getName());
084                            }
085                    }
086            }
087    
088            /**
089             * Marks the given file as used and returns the complete file (with
090             * directory).
091             */
092            public File getTestFile(String filename, TestCase testCase) {
093    
094                    HashSet<String> set = usedFiles.getValue(testCase.getClass(), testCase);
095                    if (set == null) {
096                            set = new HashSet<String>();
097                            usedFiles.putValue(testCase.getClass(), testCase, set);
098                    }
099    
100                    set.add(filename);
101                    unusedFiles.remove(filename);
102                    updateUsageReports();
103    
104                    return new File(directory, filename);
105            }
106    
107            /**
108             * Print a summary on used and unused test data files into a directory
109             * specific log file.
110             */
111            private void updateUsageReports() {
112                    try {
113                            File baseDir = new File(REPORT_DIRECTORY_NAME);
114                            FileSystemUtils.ensureDirectoryExists(baseDir);
115                            String fname = directory.toString().replaceAll("[\\\\/]", "_");
116    
117                            PrintWriter pw = new PrintWriter(new FileWriter(new File(baseDir,
118                                            fname + "_usage.txt")));
119                            printUsedFiles(pw);
120                            pw.close();
121    
122                            pw = new PrintWriter(new FileWriter(new File(baseDir, fname
123                                            + "_unusage.txt")));
124                            printUnusedFiles(pw);
125                            pw.close();
126                    } catch (IOException e) {
127                            // This is the best we can do (as we are in testing)
128                            e.printStackTrace();
129                    }
130            }
131    
132            /** Print a report on all files not used. */
133            public void printUnusedFiles(PrintWriter pw) {
134                    pw.println("Unused files for directory " + directory + ": "
135                                    + unusedFiles.size());
136                    ArrayList<String> fileList = new ArrayList<String>(unusedFiles);
137                    Collections.sort(fileList);
138                    for (String filename : fileList) {
139                            pw.print("  ");
140                            pw.println(filename);
141                    }
142    
143                    pw.flush();
144            }
145    
146            /** Print a report on all files used. */
147            public void printUsedFiles(PrintWriter pw) {
148                    pw.println("Used files for directory " + directory);
149    
150                    for (Class<?> clazz : usedFiles.getFirstKeys()) {
151                            pw.print("  ");
152                            pw.println(clazz.getName());
153                            for (TestCase testCase : usedFiles.getSecondKeys(clazz)) {
154                                    pw.print("    ");
155                                    pw.println(testCase.getName());
156                                    for (String filename : usedFiles.getValue(clazz, testCase)) {
157                                            pw.print("      ");
158                                            pw.println(filename);
159                                    }
160                            }
161                            pw.println();
162                    }
163    
164                    pw.flush();
165            }
166    
167    }