001/*-------------------------------------------------------------------------+
002|                                                                          |
003| Copyright (c) 2005-2018 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|                                                                          |
017+-------------------------------------------------------------------------*/
018package org.conqat.lib.commons.test;
019
020import java.io.File;
021import java.io.IOException;
022import java.util.Arrays;
023import java.util.List;
024import java.util.Optional;
025import java.util.function.Predicate;
026
027import org.conqat.lib.commons.collections.CollectionUtils;
028import org.conqat.lib.commons.resources.Resource;
029import org.conqat.lib.commons.resources.ResourceException;
030
031/**
032 * A test helper that provides access to a test-specific resources. Backed by a
033 * {@link TestDataManager}.
034 */
035public class ManagedTestData {
036
037        /** Test data manager for this test case. */
038        private final TestDataManager testDataManager;
039
040        /**
041         * @param contextClass
042         *            The (test) class using the managed test data. The package of the
043         *            class determines the root folder that is used for resource
044         *            lookups.
045         */
046        public ManagedTestData(Class<?> contextClass) {
047                testDataManager = TestDataManager.getInstance(contextClass);
048        }
049
050        /**
051         * Returns the given resource. The resource must be placed in the test-data
052         * folder under the package name of the contextClass. The path may also contain
053         * forward slashes to address sub-resources. The test-data directory is, for
054         * example,
055         * "engine/com.teamscale.index/test-data/com/teamscale/index/code_clones" for
056         * the context class
057         * com.teamscale.index.code_clones.TeamscaleCloneDetectionTest.
058         */
059        public Resource getResource(String path) {
060                return testDataManager.getResource(path);
061        }
062
063        /**
064         * Returns the given resource or an empty optional if no resource with the given
065         * path exists. The resource must be placed in the test-data folder under the
066         * package name of the contextClass. The path may also contain forward slashes
067         * to address sub-resources. The test-data directory is, for example,
068         * "engine/com.teamscale.index/test-data/com/teamscale/index/code_clones" for *
069         * the context class com.teamscale.index.code_clones.TeamscaleCloneDetectionTest
070         * (does not include the name of the test).
071         */
072        public Optional<Resource> getResourceIfExists(String path) {
073                if (testDataManager.hasResource(path)) {
074                        return Optional.of(testDataManager.getResource(path));
075                } else {
076                        return Optional.empty();
077                }
078        }
079
080        /**
081         * Returns the content of given resource. The content is expected to be UTF-8
082         * encoded and line separators are normalized. The resource must be placed in
083         * the test-data folder under the package name of the contextClass. The path may
084         * also contain forward slashes to address sub-resources. The test-data
085         * directory is, for example,
086         * "engine/com.teamscale.index/test-data/com/teamscale/index/code_clones" for
087         * the context class com.teamscale.index.code_clones.TeamscaleCloneDetectionTest
088         * (does not include the name of the test).
089         * 
090         * In case you need to load the non-normalized content use
091         * {@link #getResource(String)} and {@link Resource#getContentAsRawString()} or
092         * {@link Resource#getAsByteArray()} instead.
093         */
094        public String getDataContent(String path) {
095                return testDataManager.getResource(path).getContent();
096        }
097
098        /**
099         * Returns a copy of the given resource as temporary file. The original resource
100         * must be placed in the test-data folder under the package name of the
101         * contextClass. The path may also contain forward slashes to address
102         * sub-resources. The test-data directory is, for example,
103         * "engine/com.teamscale.index/test-data/com/teamscale/index/code_clones" for
104         * the context class com.teamscale.index.code_clones.TeamscaleCloneDetectionTest
105         * (does not include the name of the test).
106         *
107         * In case your test relies on the exact file name use
108         * {@link #getDataFile(String, File)} instead, which allows you to copy into a
109         * given temporary directory under the original file name.
110         */
111        public File getDataFile(String fileName) {
112                Resource resource = testDataManager.getResource(fileName);
113                try {
114                        return resource.getAsTmpFile();
115                } catch (IOException e) {
116                        throw ResourceException.newLoadFailed(resource, e);
117                }
118        }
119
120        /**
121         * Returns a copy of the given resource as temporary file. The temporary copy is
122         * stored directly in the given tempDir. The original resource must be placed in
123         * the test-data folder under the package name of the contextClass. The path may
124         * also contain forward slashes to address sub-resources. The test-data
125         * directory is, for example,
126         * "engine/com.teamscale.index/test-data/com/teamscale/index/code_clones" for
127         * the context class com.teamscale.index.code_clones.TeamscaleCloneDetectionTest
128         * (does not include the name of the test).
129         */
130        public File getDataFile(String fileName, File tempDir) {
131                Resource resource = testDataManager.getResource(fileName);
132                File newFile = new File(tempDir, fileName);
133                try {
134                        resource.copyTo(newFile);
135                } catch (IOException e) {
136                        throw ResourceException.newLoadFailed(resource, e);
137                }
138                return newFile;
139        }
140
141        /**
142         * Creates a copy of the given resource directory in the given tempDir. The
143         * original resource must be placed in the test-data folder under the package
144         * name of the contextClass. The path may also contain forward slashes to
145         * address sub-resources. The test-data directory is, for example,
146         * "engine/com.teamscale.index/test-data/com/teamscale/index/code_clones" for
147         * the context class com.teamscale.index.code_clones.TeamscaleCloneDetectionTest
148         * (does not include the name of the test).
149         * 
150         * @return The root of the directory in the temporary location.
151         */
152        public File copyDataDirectory(String directoryName, File tempDir) {
153                List<Resource> resources = testDataManager.listResourcesRecursively(directoryName);
154                for (Resource resource : resources) {
155                        try {
156                                resource.copyTo(new File(tempDir, resource.getPath()));
157                        } catch (IOException e) {
158                                throw ResourceException.newLoadFailed(resource, e);
159                        }
160                }
161                return new File(tempDir, directoryName);
162        }
163
164        /**
165         * Lists all resources contained in the given subfolder. If fileExtensions are
166         * given the resources that do not match any of them are filtered out.
167         */
168        public List<Resource> listResources(String subfolder, String... fileExtensions) {
169                return listResources(subfolder, filterByExtension(fileExtensions));
170        }
171
172        /**
173         * Lists all resources contained in the given subfolder matching the given
174         * predicate.
175         */
176        public List<Resource> listResources(String subfolder, Predicate<Resource> filter) {
177                return CollectionUtils.filter(testDataManager.listResources(subfolder), filter);
178        }
179
180        /**
181         * Lists all resources contained in the given subfolder recursively. If
182         * fileExtensions are given the resources that do not match any of them are
183         * filtered out.
184         */
185        public List<Resource> listResourcesRecursively(String subfolder, String... fileExtensions) {
186                return listResourcesRecursively(subfolder, filterByExtension(fileExtensions));
187        }
188
189        /**
190         * Lists all resources contained in the given subfolder recursively matching the
191         * given predicate.
192         */
193        public List<Resource> listResourcesRecursively(String subfolder, Predicate<Resource> filter) {
194                return CollectionUtils.filter(testDataManager.listResourcesRecursively(subfolder), filter);
195        }
196
197        private static Predicate<Resource> filterByExtension(String... fileExtensions) {
198                if (fileExtensions.length == 0) {
199                        return (resource) -> true;
200                }
201                return (resource) -> Arrays.stream(fileExtensions).anyMatch(resource::hasExtension);
202        }
203}