Coverage Report - org.jbehave.core.io.LoadFromRelativeFile
 
Classes in this File Line Coverage Branch Coverage Complexity
LoadFromRelativeFile
67%
23/34
50%
4/8
2.3
LoadFromRelativeFile$StoryFilePath
100%
5/5
N/A
2.3
 
 1  
 package org.jbehave.core.io;
 2  
 
 3  
 import java.io.File;
 4  
 import java.io.FileInputStream;
 5  
 import java.io.UnsupportedEncodingException;
 6  
 import java.net.URL;
 7  
 import java.net.URLDecoder;
 8  
 import java.util.ArrayList;
 9  
 import java.util.List;
 10  
 
 11  
 import org.apache.commons.io.IOUtils;
 12  
 
 13  
 /**
 14  
  * Loads story resources from relative file paths that are
 15  
  * traversal to a given location.
 16  
  * 
 17  
  * StoryLoader loader = new
 18  
  * LoadFromRelativeFile(codeLocationFromClass(YourStory.class));
 19  
  * 
 20  
  * By default, it uses traversal directory
 21  
  * 'target/test-classes' with source dir in 'src/test/java'.
 22  
  * 
 23  
  * Other traversal locations can be specified via the varargs constructor:
 24  
  * 
 25  
  * StoryLoader loader = new
 26  
  * LoadFromRelativeFile(codeLocationFromClass(YourStory.class),
 27  
  * mavenModuleTestStoryFilePath("src/test/java"),
 28  
  * intellijProjectTestStoryFilePath("src/test/java"));
 29  
  * 
 30  
  * Convenience methods : {@link LoadFromRelativeFile#mavenModuleStoryFilePath},
 31  
  * {@link LoadFromRelativeFile#mavenModuleTestStoryFilePath}
 32  
  * {@link LoadFromRelativeFile#intellijProjectStoryFilePath}
 33  
  * {@link LoadFromRelativeFile#intellijProjectTestStoryFilePath}
 34  
  * 
 35  
  * @see {@link CodeLocations#codeLocationFromClass(Class)}
 36  
  * 
 37  
  */
 38  
 public class LoadFromRelativeFile implements ResourceLoader, StoryLoader {
 39  
 
 40  
     private final StoryFilePath[] traversals;
 41  
     private final URL location;
 42  
 
 43  
     public LoadFromRelativeFile(URL location) {
 44  5
         this(location, mavenModuleStoryFilePath("src/test/java"));
 45  5
     }
 46  
 
 47  7
     public LoadFromRelativeFile(URL location, StoryFilePath... traversals) {
 48  7
         this.traversals = traversals;
 49  7
         this.location = location;
 50  7
     }
 51  
     
 52  
     public String loadResourceAsText(String resourcePath) {
 53  0
         List<String> traversalPaths = new ArrayList<String>();
 54  0
         String locationPath = new File(location.getFile()).getAbsolutePath();
 55  0
         for (StoryFilePath traversal : traversals) {
 56  0
             String filePath = locationPath.replace(traversal.toRemove, traversal.relativePath) + "/" + resourcePath;
 57  0
             File file = new File(filePath);
 58  0
             if (file.exists()) {
 59  0
                 return loadContent(filePath);
 60  
             } else {
 61  0
                 traversalPaths.add(filePath);
 62  
             }
 63  
         }
 64  0
         throw new StoryResourceNotFound(resourcePath, traversalPaths);
 65  
     }
 66  
 
 67  
     public String loadStoryAsText(String storyPath) {
 68  6
         List<String> traversalPaths = new ArrayList<String>();
 69  
         String locationPath;
 70  
         try {
 71  6
             locationPath = new File(URLDecoder.decode(location.getFile(), "UTF-8")).getAbsolutePath();
 72  0
         } catch (UnsupportedEncodingException e) {
 73  0
             throw new InvalidStoryResource(storyPath, e);
 74  6
         }
 75  7
         for (StoryFilePath traversal : traversals) {
 76  5
             String filePath = locationPath.replace(traversal.toRemove, traversal.relativePath) + "/" + storyPath;
 77  5
             File file = new File(filePath);
 78  5
             if (file.exists()) {
 79  4
                 return loadContent(filePath);
 80  
             } else {
 81  1
                 traversalPaths.add(filePath);
 82  
             }
 83  
         }
 84  2
         throw new StoryResourceNotFound(storyPath, traversalPaths);
 85  
     }
 86  
 
 87  
     protected String loadContent(String path) {
 88  
         try {
 89  5
             return IOUtils.toString(new FileInputStream(new File(path)));
 90  1
         } catch (Exception e) {
 91  1
             throw new InvalidStoryResource(path, e);
 92  
         }
 93  
     }
 94  
 
 95  
     /**
 96  
      * For use the the varargs constructor of {@link LoadFromRelativeFile}, to
 97  
      * allow a range of possibilities for locating Story file paths
 98  
      */
 99  10
     public static class StoryFilePath {
 100  
         private final String toRemove;
 101  
         private final String relativePath;
 102  
 
 103  9
         public StoryFilePath(String toRemove, String relativePath) {
 104  9
             this.toRemove = toRemove.replace('\\', '/');
 105  9
             this.relativePath = relativePath.replace('\\', '/');
 106  9
         }
 107  
     }
 108  
 
 109  
     /**
 110  
      * Maven by default, has its PRODUCTION classes in target/classes. This
 111  
      * story file path is relative to that.
 112  
      * 
 113  
      * @param relativePath
 114  
      *            the path to the stories' base-dir inside the module
 115  
      * @return the resulting StoryFilePath
 116  
      */
 117  
     public static StoryFilePath mavenModuleStoryFilePath(String relativePath) {
 118  6
         return new StoryFilePath("target/classes", relativePath);
 119  
     }
 120  
 
 121  
     /**
 122  
      * Maven by default, has its TEST classes in target/test-classes. This story
 123  
      * file path is relative to that.
 124  
      * 
 125  
      * @param relativePath
 126  
      *            the path to the stories' base-dir inside the module
 127  
      * @return the resulting StoryFilePath
 128  
      */
 129  
     public static StoryFilePath mavenModuleTestStoryFilePath(String relativePath) {
 130  1
         return new StoryFilePath("target/test-classes", relativePath);
 131  
     }
 132  
 
 133  
     /**
 134  
      * Intellij by default, has its PRODUCTION classes in classes/production.
 135  
      * This story file path is relative to that.
 136  
      * 
 137  
      * @param relativePath
 138  
      *            the path to the stories' base-dir inside the module
 139  
      * @return the resulting StoryFilePath
 140  
      */
 141  
     public static StoryFilePath intellijProjectStoryFilePath(String relativePath) {
 142  1
         return new StoryFilePath("classes/production", relativePath);
 143  
     }
 144  
 
 145  
     /**
 146  
      * Intellij by default, has its TEST classes in classes/test. This story
 147  
      * file path is relative to that.
 148  
      * 
 149  
      * @param relativePath
 150  
      *            the path to the stories' base-dir inside the module
 151  
      * @return the resulting StoryFilePath
 152  
      */
 153  
     public static StoryFilePath intellijProjectTestStoryFilePath(String relativePath) {
 154  1
         return new StoryFilePath("classes/test", relativePath);
 155  
     }
 156  
 
 157  
 }