1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21 package searls.jasmine.runner;
22
23 import org.antlr.stringtemplate.StringTemplate;
24 import org.antlr.stringtemplate.language.DefaultTemplateLexer;
25 import org.apache.maven.artifact.Artifact;
26 import searls.jasmine.io.FileUtilsWrapper;
27
28 import java.io.File;
29 import java.io.IOException;
30 import java.net.MalformedURLException;
31 import java.util.ArrayList;
32 import java.util.Collections;
33 import java.util.List;
34
35 public class SpecRunnerHtmlGenerator {
36
37 private static final String CSS_TYPE = "css";
38 private static final String CSS_DEPENDENCIES_TEMPLATE_ATTR_NAME = "cssDependencies";
39 private static final String JAVASCRIPT_TYPE = "js";
40 private static final String JAVASCRIPT_DEPENDENCIES_TEMPLATE_ATTR_NAME = "javascriptDependencies";
41 private static final String SOURCES_TEMPLATE_ATTR_NAME = "sources";
42 private static final String REPORTER_ATTR_NAME = "reporter";
43 private static final String RUNNER_HTML_TEMPLATE =
44 "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\" \"http://www.w3.org/TR/html4/loose.dtd\">\n" +
45 "<html>\n" +
46 "<head><title>Jasmine Test Runner</title>\n" +
47 "$"+CSS_DEPENDENCIES_TEMPLATE_ATTR_NAME+"$\n" +
48 "$"+JAVASCRIPT_DEPENDENCIES_TEMPLATE_ATTR_NAME+"$\n" +
49 "$"+SOURCES_TEMPLATE_ATTR_NAME+"$\n" +
50 "</head>\n" +
51 "<body>\n"+
52 "<script type=\"text/javascript\">var reporter = new jasmine.$"+REPORTER_ATTR_NAME+"$(); jasmine.getEnv().addReporter(reporter); jasmine.getEnv().execute();</script>" +
53 "\n</body>\n" +
54 "</html>";
55
56 public enum ReporterType { TrivialReporter, JsApiReporter };
57
58 private FileUtilsWrapper fileUtilsWrapper = new FileUtilsWrapper();
59
60 private final File sourceDir;
61 private final File specDir;
62 private final File libDir;
63 private final File baseDir;
64 private List<String> sourcesToLoadFirst;
65 private List<File> fileNamesAlreadyWrittenAsScriptTags = new ArrayList<File>();
66
67 public SpecRunnerHtmlGenerator(List<String> sourcesToLoadFirst, File sourceDir, File specDir, File libDir, File baseDir) {
68 this.sourcesToLoadFirst = sourcesToLoadFirst;
69 this.sourceDir = sourceDir;
70 this.specDir = specDir;
71 this.libDir = libDir;
72 this.baseDir = baseDir;
73 }
74
75 public String generate(List<Artifact> dependencies, ReporterType reporterType) {
76 try {
77 StringTemplate template = new StringTemplate(RUNNER_HTML_TEMPLATE,DefaultTemplateLexer.class);
78
79 includeJavaScriptAndCssDependencies(dependencies, template);
80 setJavaScriptSourcesAttribute(template);
81 template.setAttribute(REPORTER_ATTR_NAME, reporterType.name());
82
83 return template.toString();
84 } catch (IOException e) {
85 throw new RuntimeException("Failed to load file names for dependencies or scripts",e);
86 }
87 }
88
89 private void includeJavaScriptAndCssDependencies(
90 List<Artifact> dependencies, StringTemplate template)
91 throws IOException {
92 StringBuilder javaScriptDependencies = new StringBuilder();
93 StringBuilder cssDependencies = new StringBuilder();
94 for(Artifact dep : dependencies) {
95 if(JAVASCRIPT_TYPE.equals(dep.getType())) {
96 javaScriptDependencies.append("<script type=\"text/javascript\">").append(fileUtilsWrapper.readFileToString(dep.getFile())).append("</script>\n");
97 } else if(CSS_TYPE.equals(dep.getType())) {
98 cssDependencies.append("<style type=\"text/css\">\n").append(fileUtilsWrapper.readFileToString(dep.getFile())).append("\n</style>\n");
99 }
100 }
101 template.setAttribute(JAVASCRIPT_DEPENDENCIES_TEMPLATE_ATTR_NAME, javaScriptDependencies.toString());
102 template.setAttribute(CSS_DEPENDENCIES_TEMPLATE_ATTR_NAME, cssDependencies.toString());
103 }
104
105 private void setJavaScriptSourcesAttribute(StringTemplate template)
106 throws IOException {
107 StringBuilder scriptTags = new StringBuilder();
108 appendScriptTagsForFiles(scriptTags, expandSourcesToLoadFirst());
109 if( sourceDir != null && sourceDir.exists() ) {
110 appendScriptTagsForFiles(scriptTags, filesForScriptsInDirectory(sourceDir));
111 }
112 appendScriptTagsForFiles(scriptTags, filesForScriptsInDirectory(specDir));
113 template.setAttribute(SOURCES_TEMPLATE_ATTR_NAME,scriptTags.toString());
114 }
115
116 private List<File> expandSourcesToLoadFirst() {
117 List<File> files = new ArrayList<File>();
118 if(sourcesToLoadFirst != null) {
119 for(String sourceToLoadFirst : sourcesToLoadFirst) {
120 File file = new File(sourceDir,sourceToLoadFirst);
121 if( !file.exists() ) {
122 file = new File(libDir,sourceToLoadFirst);
123 }
124 files.add(file);
125 }
126 }
127 return files;
128 }
129
130 private List<File> filesForScriptsInDirectory(File directory) throws IOException {
131 List<File> files = new ArrayList<File>();
132 if(directory != null) {
133 fileUtilsWrapper.forceMkdir(directory);
134 files = new ArrayList<File>(fileUtilsWrapper.listFiles(directory, new String[] {"js"}, true));
135 Collections.sort(files);
136 }
137 return files;
138 }
139
140 private void appendScriptTagsForFiles(StringBuilder sb, List<File> sourceFiles) throws MalformedURLException {
141 for (File sourceFile : sourceFiles) {
142 if(!fileNamesAlreadyWrittenAsScriptTags.contains(sourceFile)) {
143 sb.append("<script type=\"text/javascript\" charset=\"utf-8\" src=\"").append(findRelativePath(baseDir,sourceFile)).append("\"></script>\n");
144 fileNamesAlreadyWrittenAsScriptTags.add(sourceFile);
145 }
146 }
147 }
148
149
150
151
152
153
154
155
156 public static String findRelativePath(File base, File file) throws MalformedURLException
157 {
158 String a = ( base == null ) ? ":" : base.toURI().getPath();
159 String b = file.getParentFile().toURI().getPath();
160 String[] basePaths = a.split("/");
161 String[] otherPaths = b.split("/");
162 int n = 0;
163 for (; n < basePaths.length && n < otherPaths.length; n++) {
164 if (basePaths[n].equals(otherPaths[n]) == false) {
165 break;
166 }
167 }
168 if( n == 0 ) {
169 return file.toURI().toURL().toString();
170 }
171
172 StringBuffer tmp = new StringBuffer();
173 for (int m = n; m < basePaths.length; m++) {
174 tmp.append("../");
175 }
176 for (int m = n; m < otherPaths.length; m++) {
177 tmp.append(otherPaths[m]).append("/");
178 }
179 tmp.append(file.getName());
180
181 return tmp.toString();
182 }
183 }