diff --git a/README.md b/README.md
index 9ecedee8..1916a42f 100644
--- a/README.md
+++ b/README.md
@@ -17,6 +17,12 @@ Requirements
------------
* Java 8
+1.0.5
+-----
+* Single Maven plugin, glossary functionality moved into the same plugin that provides execution and report building,
+ original glossary-builder kept in place to avoid breakages. Removed XML variant of the Glossary in favour of json.
+
+
1.0.4
-----
* Added a checkbox to the report to optionally hide skipped steps
diff --git a/core/src/main/java/com/technophobia/substeps/glossary/StepDescriptor.java b/api/src/main/java/com/technophobia/substeps/glossary/StepDescriptor.java
similarity index 100%
rename from core/src/main/java/com/technophobia/substeps/glossary/StepDescriptor.java
rename to api/src/main/java/com/technophobia/substeps/glossary/StepDescriptor.java
diff --git a/core/src/main/java/com/technophobia/substeps/glossary/StepImplementationsDescriptor.java b/api/src/main/java/com/technophobia/substeps/glossary/StepImplementationsDescriptor.java
similarity index 100%
rename from core/src/main/java/com/technophobia/substeps/glossary/StepImplementationsDescriptor.java
rename to api/src/main/java/com/technophobia/substeps/glossary/StepImplementationsDescriptor.java
diff --git a/core/src/main/java/com/technophobia/substeps/model/exception/SubstepsRuntimeException.java b/api/src/main/java/com/technophobia/substeps/model/exception/SubstepsRuntimeException.java
similarity index 100%
rename from core/src/main/java/com/technophobia/substeps/model/exception/SubstepsRuntimeException.java
rename to api/src/main/java/com/technophobia/substeps/model/exception/SubstepsRuntimeException.java
diff --git a/api/src/main/java/org/substeps/report/IReportBuilder.java b/api/src/main/java/org/substeps/report/IReportBuilder.java
index 02aeb816..a06d8632 100644
--- a/api/src/main/java/org/substeps/report/IReportBuilder.java
+++ b/api/src/main/java/org/substeps/report/IReportBuilder.java
@@ -8,5 +8,6 @@
public interface IReportBuilder {
void buildFromDirectory(File sourceDataDir);
+ void buildFromDirectory(File sourceDataDir, File stepImplsJson);
}
diff --git a/core/src/main/java/com/technophobia/substeps/glossary/XMLSubstepsGlossarySerializer.java b/core/src/main/java/com/technophobia/substeps/glossary/XMLSubstepsGlossarySerializer.java
deleted file mode 100644
index 3172fa3f..00000000
--- a/core/src/main/java/com/technophobia/substeps/glossary/XMLSubstepsGlossarySerializer.java
+++ /dev/null
@@ -1,94 +0,0 @@
-/*
- * Copyright Technophobia Ltd 2012
- *
- * This file is part of Substeps.
- *
- * Substeps is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * Substeps is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with Substeps. If not, see .
- */
-package com.technophobia.substeps.glossary;
-
-import com.thoughtworks.xstream.XStream;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.util.List;
-import java.util.jar.JarFile;
-import java.util.zip.ZipEntry;
-
-/*
- * Copyright Technophobia Ltd 2012
- *
- * This file is part of Substeps.
- *
- * Substeps is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * Substeps is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with Substeps. If not, see .
- */
-public class XMLSubstepsGlossarySerializer {
-
- public static final String XML_FILE_NAME = "substeps-metainfo.xml";
-
- private final Logger log = LoggerFactory.getLogger(XMLSubstepsGlossarySerializer.class);
-
-
- public String toXML(final List classStepTags) {
-
- final XStream xstream = new XStream();
- return xstream.toXML(classStepTags);
- }
-
-
- public List fromXML(final InputStream inputStream) {
- final XStream xstream = new XStream();
- return (List) xstream.fromXML(inputStream);
- }
-
-
- public List loadStepImplementationsDescriptorFromJar(
- final JarFile jarFileForClass) {
-
- List classStepTagList = null;
-
- final ZipEntry entry = jarFileForClass
- .getEntry(XMLSubstepsGlossarySerializer.XML_FILE_NAME);
-
- if (entry != null) {
-
- try {
- final InputStream is = jarFileForClass.getInputStream(entry);
-
- classStepTagList = fromXML(is);
-
- } catch (final IOException e) {
- log.error("Error loading from jarfile: ", e);
- }
- } else {
- log.error("couldn't locate file in jar: " + XMLSubstepsGlossarySerializer.XML_FILE_NAME);
- }
-
- return classStepTagList;
- }
-
-}
diff --git a/core/src/main/resources/static/css/glossary.css b/core/src/main/resources/static/css/glossary.css
new file mode 100644
index 00000000..a453767b
--- /dev/null
+++ b/core/src/main/resources/static/css/glossary.css
@@ -0,0 +1,7 @@
+ .dataTables_filter{
+ visibility:hidden;
+ }
+
+ #glossary-table_wrapper div.row-fluid:nth-of-type(1) {
+ display:none;
+ }
\ No newline at end of file
diff --git a/core/src/main/resources/static/js/glossary.js b/core/src/main/resources/static/js/glossary.js
new file mode 100644
index 00000000..6704bd08
--- /dev/null
+++ b/core/src/main/resources/static/js/glossary.js
@@ -0,0 +1,55 @@
+$(document).ready(function() {
+
+ var glossaryTable = $('#glossary-table').DataTable({
+ paging: false,
+ searching: true,
+ "data": glossary,
+ "columns": [
+ {data: 'section', title: "Section"},
+ {data: 'expression', title: "Expression"},
+ {data: 'description', title: "Description"},
+ {data: 'example', title: "Example"}
+ ],
+ "dom" : "<'row-fluid'<'col-sm-6'l><'col-sm-6'f>>" +
+ "<'row-fluid'<'col-sm-12'tr>>" +
+ "<'row-fluid'<'col-sm-5'i><'col-sm-7'p>>"
+ // ,
+ // sDom: '<"search-box"r><"H"lf>t<"F"ip>'
+ });
+
+$('#glossarySearchField').keyup(function(){
+ glossaryTable.search($(this).val()).draw() ;
+})
+
+
+
+
+});
+
+
+
+
+
+$('#substep-usage-show-hide').on('click', function () {
+
+ toggleShowHide(this);
+
+});
+
+$('#stepimpl-usage-show-hide').on('click', function () {
+
+ toggleShowHide(this);
+
+});
+
+function toggleShowHide(elem){
+ if ($(elem).text() == 'Hide') {
+ $(elem).text('Show')
+ }
+ else {
+ $(elem).text('Hide');
+ }
+}
+
+
+
diff --git a/core/src/main/scala/org/substeps/report/GlossaryTemplate.scala b/core/src/main/scala/org/substeps/report/GlossaryTemplate.scala
new file mode 100644
index 00000000..29514846
--- /dev/null
+++ b/core/src/main/scala/org/substeps/report/GlossaryTemplate.scala
@@ -0,0 +1,102 @@
+package org.substeps.report
+
+/**
+ * Created by ian on 06/02/17.
+ */
+trait GlossaryTemplate {
+
+ def buildGlossaryReport(dateTimeString :String) ={
+
+ s"""
+
+
+
+
+ Substeps Glossary
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Glossary
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Section
+
Expression
+
Description
+
Example
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ """
+
+ }
+}
diff --git a/core/src/main/scala/org/substeps/report/Model.scala b/core/src/main/scala/org/substeps/report/Model.scala
index ab233d7c..9f865e34 100644
--- a/core/src/main/scala/org/substeps/report/Model.scala
+++ b/core/src/main/scala/org/substeps/report/Model.scala
@@ -76,3 +76,25 @@ case object State {
case class JsTreeNode(id : String, text: String, icon : String, children : Option[List[JsTreeNode]], state : State, li_attr : Option[Map[String,String]] = None)
+case class StepImplDesc(expressions : List[StepDesc],className: String )
+
+case class StepDesc(expression: String ,
+ regex: String ,
+ example: String ,
+ section: String ,
+ description: String ,
+ parameterNames: List[String] ,
+ parameterClassNames: List[String]
+ )
+
+case class GlossaryElement(
+ section: String ,
+ expression: String ,
+
+ className: String,
+ regex: String ,
+ example: String ,
+ description: String ,
+ parameterNames: List[String] ,
+ parameterClassNames: List[String]
+ )
\ No newline at end of file
diff --git a/core/src/main/scala/org/substeps/report/ReportBuilder.scala b/core/src/main/scala/org/substeps/report/ReportBuilder.scala
index 604e1c0f..ca646db8 100644
--- a/core/src/main/scala/org/substeps/report/ReportBuilder.scala
+++ b/core/src/main/scala/org/substeps/report/ReportBuilder.scala
@@ -71,7 +71,7 @@ object ReportBuilder {
/**
* Created by ian on 30/06/16.
*/
-class ReportBuilder extends IReportBuilder with ReportFrameTemplate with UsageTreeTemplate {
+class ReportBuilder extends IReportBuilder with ReportFrameTemplate with UsageTreeTemplate with GlossaryTemplate {
@BeanProperty
var reportDir : File = new File(".")
@@ -89,8 +89,26 @@ class ReportBuilder extends IReportBuilder with ReportFrameTemplate with UsageTr
}
}
+ def buildGlossaryData(sourceJsonFile : File) = {
+ implicit val formats = Serialization.formats(NoTypeHints)
+
+ val data = read[List[StepImplDesc]](sourceJsonFile)
+
+ val glossaryElements =
+ data.map(sid => sid.expressions.map(sd => {
+ GlossaryElement(sd.section, sd.expression, sid.className, sd.regex, sd.example, sd.description, sd.parameterNames, sd.parameterClassNames)
+ })).flatten
+
+ glossaryElements
+ }
def buildFromDirectory(sourceDataDir: File): Unit = {
+ buildFromDirectory(sourceDataDir, null)
+ }
+
+ def buildFromDirectory(sourceDataDir: File, stepImplsJson : File): Unit = {
+
+
reportDir.mkdir()
@@ -116,10 +134,12 @@ class ReportBuilder extends IReportBuilder with ReportFrameTemplate with UsageTr
val stats : ExecutionStats = buildExecutionStats(srcData)
+ val localDate = LocalDateTime.ofInstant(Instant.ofEpochMilli(srcData._1.timestamp), ZoneId.systemDefault());
+ val dateTimeString = localDate.format(DateTimeFormatter.ofPattern("dd MMM yyyy HH:mm:ss"))
+
- val reportFrameHtml = buildReportFrame(srcData._1, stats
- )
+ val reportFrameHtml = buildReportFrame(srcData._1, stats, dateTimeString)
withWriter(reportFrameHTML, writer => writer.append(reportFrameHtml))
@@ -142,10 +162,35 @@ class ReportBuilder extends IReportBuilder with ReportFrameTemplate with UsageTr
withWriter(usgaeTreeHTMLFile, writer => writer.append(usageTreeHtml) )
+ createGlossary(stepImplsJson, dateTimeString)
+ }
+
+ def createGlossary(stepImplsJson : File, dateTimeString :String) = {
+
+ if (Option(stepImplsJson).isDefined) {
+ val glossaryHTML = createFile("glossary.html")
+ val glossaryContent = buildGlossaryReport(dateTimeString)
+
+ // TODO - pass in the path to step impls.json
+ val srcJsonFile = new File("/home/ian/projects/github/substeps-webdriver/target/classes/stepimplementations.json")
+
+ val glossaryData = buildGlossaryData(srcJsonFile)
+ val glossaryJsFile = createFile("glossary-data.js")
+ writeGlossaryJs(glossaryJsFile, glossaryData)
+ withWriter(glossaryHTML, writer => writer.append(glossaryContent))
+ }
}
+ def writeGlossaryJs(glossaryJSFile : File, glossaryData : List[GlossaryElement]) = {
+ withWriter(glossaryJSFile, writer => {
+ implicit val formats = Serialization.formats(NoTypeHints)
+ writer.append("var glossary=")
+ writer.append(writePretty(glossaryData))
+ writer.append(";\n")
+ })
+ }
def writeStatsJs(statsJsFile: File, stats: (List[Counters], List[Counters])) = {
diff --git a/core/src/main/scala/org/substeps/report/ReportFrame.scala b/core/src/main/scala/org/substeps/report/ReportFrame.scala
index 3b7c73bb..7f24233c 100644
--- a/core/src/main/scala/org/substeps/report/ReportFrame.scala
+++ b/core/src/main/scala/org/substeps/report/ReportFrame.scala
@@ -34,7 +34,7 @@ trait ReportFrameTemplate {
}
- def buildReportFrame(rootNodeSummary: RootNodeSummary, stats : ExecutionStats) = {
+ def buildReportFrame(rootNodeSummary: RootNodeSummary, stats : ExecutionStats, dateTimeString : String) = {
val featureProgressBlock = buildStatsBlock("Features", stats.featuresCounter)
val scenarioProgressBlock = buildStatsBlock("Scenarios", stats.scenarioCounters)
@@ -43,9 +43,6 @@ trait ReportFrameTemplate {
val reportTitle = Option(rootNodeSummary.description).getOrElse("Substeps Test Report")
- val localDate = LocalDateTime.ofInstant(Instant.ofEpochMilli(rootNodeSummary.timestamp), ZoneId.systemDefault());
- val dateTimeString = localDate.format(DateTimeFormatter.ofPattern("dd MMM yyyy HH:mm:ss"))
-
// TODO pull out some of the other things from the node summary - tags, nonfatal tags and environment
@@ -103,6 +100,7 @@ trait ReportFrameTemplate {
|
";
+
+ private static final String TABLE_ROW_FORMAT = "
%s
%s
%s
";
+
+}
diff --git a/runner/Maven/src/main/java/com/technophobia/substeps/glossary/IncludeProjectDependenciesComponentConfigurator.java b/runner/Maven/src/main/java/com/technophobia/substeps/glossary/IncludeProjectDependenciesComponentConfigurator.java
new file mode 100644
index 00000000..6a1719dc
--- /dev/null
+++ b/runner/Maven/src/main/java/com/technophobia/substeps/glossary/IncludeProjectDependenciesComponentConfigurator.java
@@ -0,0 +1,111 @@
+/*
+ * NB. Although this file is part of the Technophobia SubSteps glossary builder, this implementation was taken from
+ * http://maven.40175.n5.nabble.com/Adding-project-dependencies-and-generated-classes-to-classpath-of-my-plugin-td110119.html
+ */
+package com.technophobia.substeps.glossary;
+
+import org.codehaus.plexus.classworlds.realm.ClassRealm;
+import org.codehaus.plexus.component.configurator.AbstractComponentConfigurator;
+import org.codehaus.plexus.component.configurator.ComponentConfigurationException;
+import org.codehaus.plexus.component.configurator.ConfigurationListener;
+import org.codehaus.plexus.component.configurator.converters.composite.ObjectWithFieldsConverter;
+import org.codehaus.plexus.component.configurator.converters.special.ClassRealmConverter;
+import org.codehaus.plexus.component.configurator.expression.ExpressionEvaluationException;
+import org.codehaus.plexus.component.configurator.expression.ExpressionEvaluator;
+import org.codehaus.plexus.configuration.PlexusConfiguration;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.File;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * A custom ComponentConfigurator which adds the project's runtime classpath elements to the
+ *
+ * @author Brian Jackson
+ * @plexus.component role="org.codehaus.plexus.component.configurator.ComponentConfigurator"
+ * role-hint="include-project-dependencies"
+ * @plexus.requirement role="org.codehaus.plexus.component.configurator.converters.lookup.ConverterLookup"
+ * role-hint="default"
+ * @since Aug 1, 2008 3:04:17 PM
+ */
+public class IncludeProjectDependenciesComponentConfigurator extends AbstractComponentConfigurator {
+
+ private static final Logger logger = LoggerFactory
+ .getLogger(IncludeProjectDependenciesComponentConfigurator.class);
+
+
+ @Override
+ public void configureComponent(final Object component,
+ final PlexusConfiguration configuration,
+ final ExpressionEvaluator expressionEvaluator,
+ final ClassRealm containerRealm,
+ final ConfigurationListener listener)
+ throws ComponentConfigurationException {
+
+ addProjectDependenciesToClassRealm(expressionEvaluator, containerRealm);
+
+ converterLookup.registerConverter(new ClassRealmConverter(containerRealm));
+
+ final ObjectWithFieldsConverter converter = new ObjectWithFieldsConverter();
+
+ converter.processConfiguration(converterLookup, component, containerRealm,
+ configuration, expressionEvaluator, listener);
+ }
+
+
+ private void addProjectDependenciesToClassRealm(final ExpressionEvaluator expressionEvaluator,
+ final ClassRealm containerRealm) throws ComponentConfigurationException {
+
+ List testClasspathElements = null;
+
+ try {
+ // noinspection unchecked
+
+ testClasspathElements = (List) expressionEvaluator
+ .evaluate("${project.testClasspathElements}");
+
+ } catch (final ExpressionEvaluationException e) {
+ throw new ComponentConfigurationException(
+ "There was a problem evaluating: ${project.runtimeClasspathElements}", e);
+ }
+
+ if (testClasspathElements != null) {
+ // Add the project test dependencies to the ClassRealm
+ final URL[] testUrls = buildURLs(testClasspathElements);
+ for (final URL url : testUrls) {
+ containerRealm.addURL(url);
+
+ }
+ }
+
+ }
+
+
+ private URL[] buildURLs(final List runtimeClasspathElements)
+ throws ComponentConfigurationException {
+ // Add the projects classes and dependencies
+ final List urls = new ArrayList(runtimeClasspathElements.size());
+ for (final String element : runtimeClasspathElements) {
+ try {
+ final URL url = new File(element).toURI().toURL();
+ urls.add(url);
+
+ // System.out.println("Added to project class loader: " + url);
+ if (logger.isDebugEnabled()) {
+ logger.debug("Added to project class loader: " + url);
+ }
+ } catch (final MalformedURLException e) {
+ throw new ComponentConfigurationException("Unable to access project dependency: "
+ + element, e);
+ }
+ }
+
+ // Add the plugin's dependencies (so Trove stuff works if Trove isn't on
+ return urls.toArray(new URL[urls.size()]);
+ }
+
+}
\ No newline at end of file
diff --git a/runner/Maven/src/main/java/com/technophobia/substeps/glossary/JsonSubstepsPublisher.java b/runner/Maven/src/main/java/com/technophobia/substeps/glossary/JsonSubstepsPublisher.java
new file mode 100644
index 00000000..4586a825
--- /dev/null
+++ b/runner/Maven/src/main/java/com/technophobia/substeps/glossary/JsonSubstepsPublisher.java
@@ -0,0 +1,33 @@
+package com.technophobia.substeps.glossary;
+
+import com.google.gson.Gson;
+import com.google.gson.GsonBuilder;
+
+import java.util.Collection;
+import java.util.Map;
+
+/**
+ * Contributed to substeps by Andrew Lee
+ *
+ * A publisher which produces a json representation of the glossary.
+ *
+ * The resultant json can be used by Api Viewer
+ *
+ * @author Andrew Lee
+ */
+public class JsonSubstepsPublisher extends FileBasedGlossaryPublisher implements GlossaryPublisher {
+
+
+ @Override
+ public String getDefaultFileName() {
+ return "stepimplementations.json";
+ }
+
+ @Override
+ public String buildFileContents(final Map> sectionSorted) {
+ Gson gson = new GsonBuilder().create();
+ return gson.toJson(sectionSorted);
+ }
+
+}
\ No newline at end of file
diff --git a/runner/Maven/src/main/java/com/technophobia/substeps/glossary/MarkdownSubstepsPublisher.java b/runner/Maven/src/main/java/com/technophobia/substeps/glossary/MarkdownSubstepsPublisher.java
new file mode 100644
index 00000000..a0532825
--- /dev/null
+++ b/runner/Maven/src/main/java/com/technophobia/substeps/glossary/MarkdownSubstepsPublisher.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright Technophobia Ltd 2012
+ *
+ * This file is part of Substeps.
+ *
+ * Substeps is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Substeps is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with Substeps. If not, see .
+ */
+package com.technophobia.substeps.glossary;
+
+import org.apache.commons.lang3.StringEscapeUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.Collection;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+
+/**
+ * @author ian
+ */
+public class MarkdownSubstepsPublisher extends FileBasedGlossaryPublisher implements GlossaryPublisher {
+
+ private static final Logger log = LoggerFactory.getLogger(MarkdownSubstepsPublisher.class);
+
+ @Override
+ public String getDefaultFileName() {
+ return "stepimplementations.md";
+ }
+
+
+ /**
+ * @param sectionSorted
+ */
+ @Override
+ public String buildFileContents(final Map> sectionSorted) {
+ final StringBuilder buf = new StringBuilder();
+
+ final Set>> entrySet = sectionSorted.entrySet();
+
+ for (final Entry> e : entrySet) {
+ buf.append(String.format(TABLE_ROW_SECTION_FORMAT, e.getKey())).append("\n");
+
+ buildStepTagRows(buf, e.getValue());
+ }
+
+ buf.append("