##### Coverage Report - org.jbehave.core.io.StoryFinder

Classes in this File | Line Coverage | Branch Coverage | Complexity
StoryFinder |
97% | 45/46
100% | 10/10
| 1.4545454545454546;1.455
StoryFinder$1 |
100% | 3/3
N/A | N/A
| 1.4545454545454546;1.455
StoryFinder$2 |
100% | 3/3
N/A | N/A
| 1.4545454545454546;1.455
StoryFinder$3 |
100% | 5/5
100% | 2/2
| 1.4545454545454546;1.455

1 |  |
     package org.jbehave.core.io;
2 |  |
3 |  |
     import static java.util.Arrays.asList;
4 |  |
5 |  |
     import java.io.File;
6 |  |
     import java.net.URL;
7 |  |
     import java.util.ArrayList;
8 |  |
     import java.util.Collections;
9 |  |
     import java.util.Comparator;
10 |  |
     import java.util.List;
11 |  |
12 |  |
     import org.apache.commons.collections.CollectionUtils;
13 |  |
     import org.apache.commons.collections.Transformer;
14 |  |
     import org.apache.commons.lang.StringUtils;
15 |  |
     import org.codehaus.plexus.util.DirectoryScanner;
16 |  |
17 |  |
     /**
18 |  |
      * Finds stories by scanning source paths, which can be either filesystem
19 |  |
      * directories or jars. Jars are identified by paths ending in ".jar".
20 |  |
      *
21 |  |
      * Stories can be either in the form of class names or story paths.
22 |  |
      *
23 |  |
      * Stories can be sorted by providing a sorting comparator.
24 |  |
      */
25 |  |
     public class StoryFinder {
26 |  |
27 |  |
         private static final String JAR = ".jar";
28 |  |
         private static final String JAVA = ".java";
29 |  |
         private final String classNameExtension;
30 |  |
         private final Comparator<? super String> sortingComparator;
31 |  |
32 |  |
         public StoryFinder() {
33 | 14 |
             this(JAVA);
34 | 14 |
         }
35 |  |
36 |  |
         public StoryFinder(String classNameExtension) {
37 | 15 |
             this(classNameExtension, null);
38 | 15 |
         }
39 |  |
40 |  |
         public StoryFinder(Comparator<? super String> sortingComparator) {
41 | 1 |
             this(JAVA, sortingComparator);
42 | 1 |
         }
43 |  |
44 | 16 |
         private StoryFinder(String classNameExtension, Comparator<? super String> sortingComparator) {
45 | 16 |
             this.classNameExtension = classNameExtension;
46 | 16 |
             this.sortingComparator = sortingComparator;
47 | 16 |
         }
48 |  |
49 |  |
         /**
50 |  |
          * Finds Java classes from a source path, allowing for includes/excludes,
51 |  |
          * and converts them to class names.
52 |  |
          *
53 |  |
          * @param searchIn the path to search in
54 |  |
          * @param includes the List of include patterns, or <code>null</code> if
55 |  |
          *            none
56 |  |
          * @param excludes the List of exclude patterns, or <code>null</code> if
57 |  |
          *            none
58 |  |
          * @return A List of class names found
59 |  |
          */
60 |  |
         public List<String> findClassNames(String searchIn, List<String> includes, List<String> excludes) {
61 | 4 |
             return classNames(normalise(sort(scan(searchIn, includes, excludes))));
62 |  |
         }
63 |  |
64 |  |
         /**
65 |  |
          * Finds paths from a source URL, allowing for single include/exclude
66 |  |
          * pattern. Paths found are normalised by {@link
67 |  |
          * StoryFinder#normalise(List<String>)}
68 |  |
          *
69 |  |
          * @param searchIn the source URL to search in
70 |  |
          * @param include the include pattern, or <code>""</code> if none
71 |  |
          * @param exclude the exclude pattern, or <code>""</code> if none
72 |  |
          * @return A List of paths found
73 |  |
          */
74 |  |
         public List<String> findPaths(URL searchIn, String include, String exclude) {
75 | 2 |
             return findPaths(CodeLocations.getPathFromURL(searchIn), asList(include), asList(exclude));
76 |  |
         }
77 |  |
78 |  |
         /**
79 |  |
          * Finds paths from a source URL, allowing for includes/excludes,
80 |  |
          * pattern. Paths found are normalised by {@link
81 |  |
          * StoryFinder#normalise(List<String>)}
82 |  |
          *
83 |  |
          * @param searchIn the source URL to search in
84 |  |
          * @param includes the List of include patterns, or <code>null</code> if
85 |  |
          *            none
86 |  |
          * @param excludes the List of exclude patterns, or <code>null</code> if
87 |  |
          *            none
88 |  |
          * @return A List of paths found
89 |  |
          */
90 |  |
         public List<String> findPaths(URL searchIn, List<String> includes, List<String> excludes) {
91 | 0 |
             return findPaths(CodeLocations.getPathFromURL(searchIn), includes, excludes);
92 |  |
         }
93 |  |
94 |  |
         /**
95 |  |
          * Finds paths from a source path, allowing for single include/exclude
96 |  |
          * pattern. Paths found are normalised by {@link
97 |  |
          * StoryFinder#normalise(List<String>)}
98 |  |
          *
99 |  |
          * @param searchIn the source path to search in
100 |  |
          * @param include the include pattern, or <code>""</code> if none
101 |  |
          * @param exclude the exclude pattern, or <code>""</code> if none
102 |  |
          * @return A List of paths found
103 |  |
          */
104 |  |
         public List<String> findPaths(String searchIn, String include, String exclude) {
105 | 1 |
             return findPaths(searchIn, asList(include), asList(exclude));
106 |  |
         }
107 |  |
108 |  |
         /**
109 |  |
          * Finds paths from a source path, allowing for includes/excludes. Paths
110 |  |
          * found are normalised by {@link StoryFinder#normalise(List<String>)}.
111 |  |
          *
112 |  |
          * @param searchIn the source path to search in
113 |  |
          * @param includes the List of include patterns, or <code>null</code> if
114 |  |
          *            none
115 |  |
          * @param excludes the List of exclude patterns, or <code>null</code> if
116 |  |
          *            none
117 |  |
          * @return A List of paths found
118 |  |
          */
119 |  |
         public List<String> findPaths(String searchIn, List<String> includes, List<String> excludes) {
120 | 7 |
             return normalise(sort(scan(searchIn, includes, excludes)));
121 |  |
         }
122 |  |
123 |  |
         /**
124 |  |
          * Finds paths from a source path, allowing for includes/excludes. Paths
125 |  |
          * found are prefixed with specified path by {@link
126 |  |
          * StoryFinder#prefix(String, List<String>)} and normalised by {@link
127 |  |
          * StoryFinder#normalise(List<String>)}.
128 |  |
          *
129 |  |
          * @param searchIn the source path to search in
130 |  |
          * @param includes the List of include patterns, or <code>null</code> if
131 |  |
          *            none
132 |  |
          * @param excludes the List of exclude patterns, or <code>null</code> if
133 |  |
          *            none
134 |  |
          * @param prefixWith the root path prefixed to all paths found, or
135 |  |
          *            <code>null</code> if none
136 |  |
          * @return A List of paths found
137 |  |
          */
138 |  |
         public List<String> findPaths(String searchIn, List<String> includes, List<String> excludes, String prefixWith) {
139 | 2 |
             return normalise(prefix(prefixWith, sort(scan(searchIn, includes, excludes))));
140 |  |
         }
141 |  |
142 |  |
         protected List<String> normalise(List<String> paths) {
143 | 15 |
             List<String> transformed = new ArrayList<String>(paths);
144 | 15 |
             CollectionUtils.transform(transformed, new Transformer() {
145 |  |
                 public Object transform(Object input) {
146 | 127 |
                     String path = (String) input;
147 | 127 |
                     return path.replace('\\', '/');
148 |  |
                 }
149 |  |
             });
150 | 15 |
             return transformed;
151 |  |
         }
152 |  |
153 |  |
         protected List<String> prefix(final String prefixWith, List<String> paths) {
154 | 2 |
             if (StringUtils.isBlank(prefixWith)) {
155 | 1 |
                 return paths;
156 |  |
             }
157 | 1 |
             List<String> transformed = new ArrayList<String>(paths);
158 | 1 |
             CollectionUtils.transform(transformed, new Transformer() {
159 |  |
                 public Object transform(Object input) {
160 | 4 |
                     String path = (String) input;
161 | 4 |
                     return prefixWith + path;
162 |  |
                 }
163 |  |
             });
164 | 1 |
             return transformed;
165 |  |
         }
166 |  |
167 |  |
         protected List<String> classNames(List<String> paths) {
168 | 4 |
             List<String> trasformed = new ArrayList<String>(paths);
169 | 4 |
             CollectionUtils.transform(trasformed, new Transformer() {
170 |  |
                 public Object transform(Object input) {
171 | 8 |
                     String path = (String) input;
172 | 8 |
                     if (!StringUtils.endsWithIgnoreCase(path, classNameExtension())) {
173 | 1 |
                         return input;
174 |  |
                     }
175 | 7 |
                     return StringUtils.removeEndIgnoreCase(path, classNameExtension()).replace('/', '.');
176 |  |
                 }
177 |  |
             });
178 | 4 |
             return trasformed;
179 |  |
         }
180 |  |
181 |  |
         protected String classNameExtension() {
182 | 15 |
             return classNameExtension;
183 |  |
         }
184 |  |
185 |  |
         protected List<String> sort(List<String> input) {
186 | 13 |
             List<String> sorted = new ArrayList<String>(input);
187 | 13 |
             Collections.sort(sorted, sortingComparator());
188 | 13 |
             return sorted;
189 |  |
         }
190 |  |
191 |  |
         /**
192 |  |
          * Comparator used for sorting. A <code>null</code> comparator means that
193 |  |
          * {@link Collections#sort()} will use natural ordering.
194 |  |
          *
195 |  |
          * @return A Comparator or <code>null</code> for natural ordering.
196 |  |
          */
197 |  |
         protected Comparator<? super String> sortingComparator() {
198 | 13 |
             return sortingComparator;
199 |  |
         }
200 |  |
201 |  |
         protected List<String> scan(String source, List<String> includes, List<String> excludes) {
202 | 13 |
             if (source.endsWith(JAR)) {
203 | 2 |
                 return scanJar(source, includes, excludes);
204 |  |
             }
205 | 11 |
             return scanDirectory(source, includes, excludes);
206 |  |
         }
207 |  |
208 |  |
         private List<String> scanDirectory(String basedir, List<String> includes, List<String> excludes) {
209 | 11 |
             DirectoryScanner scanner = new DirectoryScanner();
210 | 11 |
             if (!new File(basedir).exists()) {
211 | 1 |
                 return new ArrayList<String>();
212 |  |
             }
213 | 10 |
             scanner.setBasedir(basedir);
214 | 10 |
             if (includes != null) {
215 | 9 |
                 scanner.setIncludes(includes.toArray(new String[includes.size()]));
216 |  |
             }
217 | 10 |
             if (excludes != null) {
218 | 9 |
                 scanner.setExcludes(excludes.toArray(new String[excludes.size()]));
219 |  |
             }
220 | 10 |
             scanner.scan();
221 | 10 |
             return asList(scanner.getIncludedFiles());
222 |  |
         }
223 |  |
224 |  |
         protected List<String> scanJar(String jarPath, List<String> includes, List<String> excludes) {
225 | 2 |
             return new JarFileScanner(jarPath, includes, excludes).scan();
226 |  |
         }
227 |  |
228 |  |
     }