001/*-------------------------------------------------------------------------+
002|                                                                          |
003| Copyright 2005-2011 The ConQAT Project                                   |
004|                                                                          |
005| Licensed under the Apache License, Version 2.0 (the "License");          |
006| you may not use this file except in compliance with the License.         |
007| You may obtain a copy of the License at                                  |
008|                                                                          |
009|    http://www.apache.org/licenses/LICENSE-2.0                            |
010|                                                                          |
011| Unless required by applicable law or agreed to in writing, software      |
012| distributed under the License is distributed on an "AS IS" BASIS,        |
013| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
014| See the License for the specific language governing permissions and      |
015| limitations under the License.                                           |
016+-------------------------------------------------------------------------*/
017package org.conqat.lib.commons.test;
018
019import java.util.Collections;
020import java.util.HashMap;
021import java.util.HashSet;
022import java.util.List;
023import java.util.Map;
024import java.util.Set;
025
026import org.conqat.lib.commons.resources.Resource;
027import org.conqat.lib.commons.resources.ResourceUtils;
028import org.conqat.lib.commons.string.StringUtils;
029
030/**
031 * Support class for loading and identifying unused test data files. This class
032 * provides a method to access test data resources. Unused resources are
033 * reported via {@link UnusedResourcesChecker} after tests have finished.
034 * 
035 * The class should only be used by {@link ManagedTestData} therefore package
036 * visibility.
037 */
038/* package */ public class TestDataManager {
039
040        /** Map of all instances (which is indexed by managed directory). */
041        private static Map<Class<?>, TestDataManager> instances = new HashMap<>();
042
043        /** Returns the instance of the test data manager for the given class. */
044        public static synchronized TestDataManager getInstance(Class<?> contextClass) {
045                if (!instances.containsKey(contextClass)) {
046                        instances.put(contextClass, new TestDataManager(contextClass));
047                }
048                return instances.get(contextClass);
049        }
050
051        /**
052         * The set of all test resources that would have been reachable from the context
053         * classes that have been used to load resources.
054         */
055        private static final Set<Resource> ALL_DATA_FILES = Collections.synchronizedSet(new HashSet<>());
056
057        /**
058         * The set of used test resources that have actually been loaded. This is just
059         * needed to determine which of the resources are unused.
060         */
061        private static final Set<Resource> USED_DATA_FILES = Collections.synchronizedSet(new HashSet<>());
062
063        /** The class this manager was instantiated for. */
064        private final Class<?> contextClass;
065
066        /** Private constructor. */
067        private TestDataManager(Class<?> contextClass) {
068                this.contextClass = contextClass;
069                ALL_DATA_FILES.addAll(ResourceUtils.listResourcesRecursively(contextClass, StringUtils.EMPTY_STRING));
070        }
071
072        /** Checks whether a resource with the given name exists. */
073        public boolean hasResource(String fileName) {
074                return Resource.exists(contextClass, fileName);
075        }
076
077        /**
078         * Marks the given resource as used and returns it.
079         */
080        public Resource getResource(String fileName) {
081                Resource resource = Resource.of(contextClass, fileName);
082                markUsed(resource);
083                return resource;
084        }
085
086        /**
087         * Lists the resources contained in the given directory and marks them all as
088         * used.
089         */
090        public List<Resource> listResources(String directory) {
091                List<Resource> resources = ResourceUtils.listResources(contextClass, directory);
092                resources.forEach(this::markUsed);
093                return resources;
094        }
095
096        /**
097         * Lists the resources contained in the given directory recursively and marks
098         * them all as used.
099         */
100        public List<Resource> listResourcesRecursively(String directory) {
101                List<Resource> resources = ResourceUtils.listResourcesRecursively(contextClass, directory);
102                resources.forEach(this::markUsed);
103                return resources;
104        }
105
106        /** Stored the given resource as used. */
107        private synchronized void markUsed(Resource resource) {
108                USED_DATA_FILES.add(resource);
109        }
110
111        /** Returns a set of all unused resources. */
112        /* package */ static Set<Resource> getUnusedResources() {
113                Set<Resource> unusedDataFiles = new HashSet<>(ALL_DATA_FILES);
114                unusedDataFiles.removeAll(USED_DATA_FILES);
115                return unusedDataFiles;
116        }
117}