diff --git a/CHANGELOG.md b/CHANGELOG.md
index 50d57f2..c1eb3cc 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,20 @@
+## [4.10.0](https://github.com/extent-framework/extentreports-java/compare/v4.0.9...v4.1.0)
+#### Improvements
+* [#18] Steps count in dashboard displays 0 even though there are logged steps
+* [#94] Cleanup tag view naming
+* [#103] AppendExisting functionality similar to version 3 API, via `JsonFormatter` and `ExtentReports::createDomainFromJsonArchive`:
+```java
+JsonFormatter json = new JsonFormatter("target/test.json");
+extent.attachReporter(json);
+extent.createDomainFromJsonArchive("target/test.json");
+```
+* [#107] ExtentSparkReporter's default view is SPA, similar to V3HtmlReporter. This can be changed by instantiating as `new ExtentSparkReporter("dir", ViewStyle.DEFAULT);`
+* [#108] All resources migrated to jsDelivr
+
+#### Fixes
+* [#57] ExtentKlovReporter: Screenshot cannot be saved in base64 format
+* [#101] Fixes Freemarker templating error
+
## [4.0.9](https://github.com/extent-framework/extentreports-java/compare/v4.0.8...v4.0.9)
#### Improvements
* [#35] HtmlReporter, BDD: description to appear as tooltip instead of newline
diff --git a/Contributing.md b/Contributing.md
new file mode 100644
index 0000000..32c2428
--- /dev/null
+++ b/Contributing.md
@@ -0,0 +1,49 @@
+# Reporting a Bug
+
+The way you report a bug is the most critical part for a quick resolution. Bugs which lack clear description and steps to reproduce are often not fixed. If you find a bug please make sure that you log the bug based on the template below. Make sure that you are as descriptive as possible.
+
+## Bug Template
+
+### Title: Line of text which summarizes what the bug is about. (Max 70 characters)
+
+- Be short and precise
+- Use simple language and grammar
+- Summarize what the issue is and nothing else
+
+### Description: Describe the issue in a few lines using simple words
+
+While describing a bug consider that you are describing it to someone who knows nothing about your problem. Be as elaborate as possible but avoid being verbose. Being verbose here would mean.
+- Providing unnecessary details without which the bug can still be described.
+
+In most of the cases, try to understand the bug in such a way that you can separate program can be written just to reproduce the issue. If you are not able to understand the bug at this moment, just try to recreate the problem with simplest possible code.
+
+### Things to include in the Description
+- What went wrong? for e.g. Adding a long description to a test results in truncation of the text.
+- When it went wrong? for e.g. If you add a text description which is greater than 255 characters, the description text gets truncated
+
+Things to NOT include in the Description
+- You application specific details. For example, do not give elaborate background on what your application does.
+- Talking about functions/code which is very specific to your project. We would not know about that.
+
+### Steps to Reproduce:
+- Detailed and precise steps to reproduce the bugs.
+- Make sure that preconditions are specified. For e.g. include a particular library or tool which is necessary to reproduce the scenario.
+- If possible you can attach images with annotations explaining where the problem is.
+- If possible create a piece of code which can reproduce the issue without having any of your application/framework code.
+
+### Expected Results
+In the end make sure that you clearly explain what were you expecting. Being very clear here is the key.
+
+
+# What happens after you have logged the bug?
+
+We look at bugs periodically. As this is an open source project, we invest time based on the availability. You can expect a reply within 2 - 3 days. If you donot get a reply, please add any of the contributors in the list.
+
+You can also raise a PR if you know the fix. PR's are always welcome. Please see the code contribution guidelines below.
+
+
+
+
+
+
+
diff --git a/config/spark-config.xml b/config/spark-config.xml
index 0d40510..5da2252 100644
--- a/config/spark-config.xml
+++ b/config/spark-config.xml
@@ -14,6 +14,9 @@
https
+
+ false
+
Extent Framework
diff --git a/config/v3html-config.xml b/config/v3html-config.xml
index 0d40510..5da2252 100644
--- a/config/v3html-config.xml
+++ b/config/v3html-config.xml
@@ -14,6 +14,9 @@
https
+
+ false
+
Extent Framework
diff --git a/pom-nexus.xml b/pom-nexus.xml
index 04f82ab..7c091b2 100644
--- a/pom-nexus.xml
+++ b/pom-nexus.xml
@@ -1,10 +1,11 @@
-4.0.0com.aventstackextentreports
- 4.0.9
+ 4.1.2-SNAPSHOTextentreportswww.extentreports.com
@@ -18,8 +19,8 @@
- The BSD 3-Clause License
- http://opensource.org/licenses/BSD-3-Clause
+ The Apache Software License, Version 2.0
+ http://www.apache.org/licenses/LICENSE-2.0.txt
@@ -36,7 +37,7 @@
UTF-8
- 3.3.0
+ 3.12.04.5.2
@@ -44,17 +45,7 @@
org.freemarkerfreemarker
- 2.3.23
-
-
- org.mongodb
- mongodb-driver
- ${mongodb.version}
-
-
- org.mongodb
- bson
- ${mongodb.version}
+ 2.3.29org.apache.httpcomponents
@@ -69,7 +60,17 @@
com.google.code.gsongson
- 2.8.5
+ 2.8.6
+
+
+ org.mongodb
+ mongodb-driver
+ ${mongodb.version}
+
+
+ org.mongodb
+ bson
+ ${mongodb.version}org.testng
@@ -159,7 +160,7 @@
- 7A7DAF8A
+ 41414BBDanshooarora
diff --git a/pom.xml b/pom.xml
index fb167f9..ed96e71 100644
--- a/pom.xml
+++ b/pom.xml
@@ -1,10 +1,11 @@
-4.0.0com.aventstackextentreports
- 4.0.9
+ 4.1.2-SNAPSHOTextentreportswww.extentreports.com
@@ -18,8 +19,8 @@
- The BSD 3-Clause License
- http://opensource.org/licenses/BSD-3-Clause
+ The Apache Software License, Version 2.0
+ http://www.apache.org/licenses/LICENSE-2.0.txt
@@ -36,7 +37,7 @@
UTF-8
- 3.3.0
+ 3.12.04.5.2
@@ -44,17 +45,7 @@
org.freemarkerfreemarker
- 2.3.23
-
-
- org.mongodb
- mongodb-driver
- ${mongodb.version}
-
-
- org.mongodb
- bson
- ${mongodb.version}
+ 2.3.29org.apache.httpcomponents
@@ -69,12 +60,22 @@
com.google.code.gsongson
- 2.8.5
+ 2.8.6
+
+
+ org.mongodb
+ mongodb-driver
+ ${mongodb.version}
+
+
+ org.mongodb
+ bson
+ ${mongodb.version}org.testngtestng
- 6.9.10
+ 6.14.3test
diff --git a/src/main/java/com/aventstack/extentreports/AnalysisStrategy.java b/src/main/java/com/aventstack/extentreports/AnalysisStrategy.java
index aff7853..fdfca02 100644
--- a/src/main/java/com/aventstack/extentreports/AnalysisStrategy.java
+++ b/src/main/java/com/aventstack/extentreports/AnalysisStrategy.java
@@ -5,15 +5,12 @@
*
* Available strategies are:
*
- *
BDD: Strategy for BDD-style (Gherkin) tests
- *
CLASS: Used for 2 levels: Class, Test
- *
SUITE: Used for 3 levels: Suite, Class, Test
- *
TEST: Used for 1 level only: Test
+ *
BDD: Strategy for BDD-style (Gherkin) tests
+ *
CLASS: Used for 2 levels: Class, Test
+ *
SUITE: Used for 3 levels: Suite, Class, Test
+ *
TEST: Used for 1 level only: Test
*
*/
public enum AnalysisStrategy {
- BDD,
- CLASS,
- SUITE,
- TEST
-}
+ BDD, CLASS, SUITE, TEST
+}
\ No newline at end of file
diff --git a/src/main/java/com/aventstack/extentreports/ExceptionTestContextImpl.java b/src/main/java/com/aventstack/extentreports/ExceptionTestContextImpl.java
deleted file mode 100644
index 502ca35..0000000
--- a/src/main/java/com/aventstack/extentreports/ExceptionTestContextImpl.java
+++ /dev/null
@@ -1,48 +0,0 @@
-package com.aventstack.extentreports;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Optional;
-
-import com.aventstack.extentreports.model.ExceptionInfo;
-import com.aventstack.extentreports.model.ExceptionTestContext;
-import com.aventstack.extentreports.model.Test;
-
-/**
- * Provides and tracks the collection of tests segregated by the type of {@link Exception}
- *
- */
-public class ExceptionTestContextImpl {
- private List exTestContextList;
-
- public ExceptionTestContextImpl() {
- exTestContextList = new ArrayList<>();
- }
-
- public void setExceptionContext(ExceptionInfo ei, Test test) {
- Optional exOptionalTestContext = exTestContextList
- .stream()
- .filter(x -> x.getExceptionInfo().getExceptionName().equals(ei.getExceptionName()))
- .findFirst();
-
- if (exOptionalTestContext.isPresent()) {
- List testList = exOptionalTestContext.get().getTestList();
-
- boolean b = testList.stream()
- .anyMatch(t -> t.getID() == test.getID());
-
- if (!b) {
- exOptionalTestContext.get().setTest(test);
- }
- }
- else {
- ExceptionTestContext exTestContext = new ExceptionTestContext(ei);
- exTestContext.setTest(test);
- exTestContextList.add(exTestContext);
- }
- }
-
- public List getExceptionTestContextList() {
- return exTestContextList;
- }
-}
diff --git a/src/main/java/com/aventstack/extentreports/ExtentObservable.java b/src/main/java/com/aventstack/extentreports/ExtentObservable.java
deleted file mode 100644
index 266dbb5..0000000
--- a/src/main/java/com/aventstack/extentreports/ExtentObservable.java
+++ /dev/null
@@ -1,611 +0,0 @@
-package com.aventstack.extentreports;
-
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.Calendar;
-import java.util.Date;
-import java.util.EnumMap;
-import java.util.List;
-import java.util.Map;
-import java.util.stream.Collectors;
-
-import com.aventstack.extentreports.model.Author;
-import com.aventstack.extentreports.model.Category;
-import com.aventstack.extentreports.model.Device;
-import com.aventstack.extentreports.model.Log;
-import com.aventstack.extentreports.model.ScreenCapture;
-import com.aventstack.extentreports.model.Screencast;
-import com.aventstack.extentreports.model.SystemAttribute;
-import com.aventstack.extentreports.model.Test;
-import com.aventstack.extentreports.reporter.BasicFileReporter;
-
-abstract class ExtentObservable
- implements ReportService {
-
- /**
- * The current AnalysisStrategy for the run session. This decides the technique used
- * to count the test status at differing levels. For example, for a BDD style report,
- * the levels to be calculated are Feature, Scenario and Step (3 levels). For a generic,
- * non-BDD style report, levels can be dynamic. For a non-BDD style report, levels typically
- * consist of:
- *
- *
- * 1 level: Test
- * Test
- * - Event
- *
- *
- * 2 levels: Test & node
- * Test - Node -- Event
- *
- *
- * 2 levels: Test, the leaf-node
- * Test - Node -- Leaf Node --- Event
- *
- */
- private AnalysisStrategy strategy = AnalysisStrategy.TEST;
-
- /**
- * Use this setting when building post-execution reports, such as from TestNG IReporter.
- * This setting allows setting test with your own variables and prevent update by Extent.
- * As of today, with this enabled, Extent does not use time-stamps for tests at the time
- * they were created
- */
- private boolean usesManualConfiguration = false;
-
- /**
- * The status of the entire report or build
- */
- private Status reportStatus = Status.PASS;
-
- /**
- * Time the report or build was started
- */
- private Date reportStartDate = Calendar.getInstance().getTime();
-
- /**
- * Time the report or build ended. This value is updated everytime flush
- * is called
- */
- private Date reportEndDate;
-
- /**
- * A collection of tests arranged by category
- */
- private TestAttributeTestContextProvider categoryContext = new TestAttributeTestContextProvider<>();
-
- /**
- * A collection of tests arranged by author
- */
- private TestAttributeTestContextProvider authorContext = new TestAttributeTestContextProvider<>();
-
- /**
- * A collection of tests arranged by author
- */
- private TestAttributeTestContextProvider deviceContext = new TestAttributeTestContextProvider<>();
-
-
- /**
- * A collection of tests arranged by exception
- */
- private ExceptionTestContextImpl exceptionContextBuilder = new ExceptionTestContextImpl();
-
- /**
- * A context of all system or environment variables
- */
- private SystemAttributeContext systemAttributeContext = new SystemAttributeContext();
-
- /**
- * A list of all {@link ExtentReporter} reporters started by the attachReporter
- * method
- */
- private List reporterList = new ArrayList<>();
-
- /**
- * Any logs added by to the test runner can be added to Extent
- *
- *
- * TestNG Example:
- *
- *
- * Setting logs with TestNG:
- *
- *
Reporter.log("hello world")
- *
- *
- * Informing Extent of any logs added:
- *
- * for (String s : Reporter.getOutput()) {
- * extent.setTestRunnerOutput(s);
- * }
- *
- */
- private List testRunnerLogs = new ArrayList<>();
-
- /**
- * A list of all tests created
- */
- private List testList = new ArrayList<>();
-
- /**
- * Instance of {@link ReportStatusStats}
- */
- private ReportStatusStats stats = new ReportStatusStats(strategy);
-
- /**
- * A unique list of status tests are marked with
- *
- *
- * Consider a report having 10 tests:
- *
- *
- *
Test1: PASS
- *
Test2: PASS
- *
Test3: PASS
- *
Test4: SKIP
- *
Test5: SKIP
- *
Test6: FAIL
- *
Test7: PASS
- *
Test8: PASS
- *
Test9: FAIL
- *
Test10: PASS
- *
- *
- *
- * Distinct list of contained status:
- *
- *
- *
PASS
- *
SKIP
- *
FAIL
- *
- */
- private List statusList = new ArrayList<>();
-
- /**
- * Contains status as keys, which are translated over to statusList
- */
- private Map statusMap = new EnumMap<>(Status.class);
-
- protected ExtentObservable() { }
-
- /**
- * Subscribe the reporter to receive updates when making calls to the API
- *
- * @param reporter {@link ExtentReporter} reporter
- */
- protected void register(ExtentReporter reporter) {
- reporterList.add(reporter);
- reporter.start();
- }
-
- /**
- * Unsubscribe the reporter. Calling unsubscribe will call the stop method
- * and also remove the reporter from the list of started reporters
- *
- * @param reporter {@link ExtentReporter} reporter to unsubscribe
- */
- protected void deregister(ExtentReporter reporter) {
- reporter.stop();
- reporterList.remove(reporter);
- }
-
- /**
- * Retrieve a list of all started reporters
- *
- * @return a list of {@link ExtentReporter} objects
- */
- protected List getReporterCollection() {
- return reporterList;
- }
-
- /**
- * Saves the started test and notifies all started reporters
- *
- * @param test a {@link Test} object
- */
- protected synchronized void saveTest(Test test) {
- testList.add(test);
- reporterList.forEach(x -> x.onTestStarted(test));
- }
-
- /**
- * Removes the test and notifies all started reporters
- *
- * @param test a {@link Test} object
- */
- protected synchronized void removeTest(Test test) {
- removeTestTestList(test);
- removeTestTestAttributeContext(test);
- reporterList.forEach(x -> x.onTestRemoved(test));
- }
-
- /**
- * Removes a test from test list
- *
- * @param test a {@link Test} object
- */
- private void removeTestTestList(Test test) {
- TestRemover.remove(testList, test);
- refreshReportEntities();
- }
-
- /**
- * Removes test from test list of each context
- *
- * @param test a {@link Test} object
- */
- private void removeTestTestAttributeContext(Test test) {
- if (test.hasCategory()) {
- categoryContext.removeTest(test);
- }
- if (test.hasAuthor()) {
- authorContext.removeTest(test);
- }
- if (test.hasDevice()) {
- deviceContext.removeTest(test);
- }
- }
-
- /**
- * Refreshes report entities such as {@link ReportStatusStats} and list of distinct {@link Status}
- */
- private void refreshReportEntities() {
- refreshReportStats();
- refreshStatusList();
- }
-
- /**
- * Refresh and notify all reports of {@link ReportStatusStats}
- */
- private void refreshReportStats() {
- stats.refresh(testList);
- }
-
- /**
- * Refresh and notify all reports of distinct status assigned to tests
- */
- private void refreshStatusList() {
- statusMap.clear();
- statusList.clear();
- refreshStatusList(testList);
- statusMap.forEach((k,v) -> statusList.add(k));
- }
-
- /**
- * Refreshes distinct status list
- *
- * @param list a list of started {@link Test}
- */
- private void refreshStatusList(List list) {
- if (list == null || list.isEmpty())
- return;
-
- list.stream()
- .map(Test::getStatus)
- .distinct()
- .collect(Collectors.toList())
- .forEach(x -> statusMap.put(x, false));
-
- list.forEach(x -> refreshStatusList(x.getNodeContext().getAll()));
- }
-
- /**
- * Notify reporters of the added node
- *
- * @param node a {@link Test} node
- */
- synchronized void addNode(Test node) {
- reporterList.forEach(x -> x.onNodeStarted(node));
- }
-
- /**
- * Notifies reporters with information of added {@link Log}
- *
- * @param test {@link Test} to which the event is added
- * @param log {@link Log}
- */
- synchronized void addLog(Test test, Log log) {
- collectRunInfo();
- reporterList.forEach(x -> x.onLogAdded(test, log));
- }
-
- /**
- * Notifies reporters with information of added {@link Category}
- *
- * @param test {@link Test} to which the Category is added
- * @param category {@link Category}
- */
- synchronized void assignCategory(Test test, Category category) {
- reporterList.forEach(x -> x.onCategoryAssigned(test, category));
- }
-
- /**
- * Notifies reporters with information of added {@link Author}
- *
- * @param test {@link Test} to which the Author is added
- * @param author {@link Author}
- */
- synchronized void assignAuthor(Test test, Author author) {
- reporterList.forEach(x -> x.onAuthorAssigned(test, author));
- }
-
- /**
- * Notifies reporters with information of added {@link Author}
- *
- * @param test {@link Test} to which the Device is added
- * @param device {@link Device}
- */
- synchronized void assignDevice(Test test, Device device) {
- reporterList.forEach(x -> x.onDeviceAssigned(test, device));
- }
-
- /**
- * Notifies reporters with information of added {@link ScreenCapture}
- *
- * @param test {@link Test} to which the ScreenCapture is added
- * @param screenCapture {@link ScreenCapture}
- *
- * @throws IOException thrown if the {@link ScreenCapture} is not found
- */
- synchronized void addScreenCapture(Test test, ScreenCapture screenCapture) throws IOException {
- for (ExtentReporter r : reporterList) {
- r.onScreenCaptureAdded(test, screenCapture);
- }
- }
-
- /**
- * Notifies reporters with information of added {@link ScreenCapture}
- *
- * @param test {@link Log} to which the ScreenCapture is added
- * @param screenCapture {@link ScreenCapture}
- *
- * @throws IOException thrown if the {@link ScreenCapture} is not found
- */
- synchronized void addScreenCapture(Log log, ScreenCapture screenCapture) throws IOException {
- for (ExtentReporter r : reporterList) {
- r.onScreenCaptureAdded(log, screenCapture);
- }
- }
-
- /**
- * Notifies reporters with information of added {@link Screencast}
- *
- * @param test {@link Test} to which the ScreenCast is added
- * @param sc {@link Screencast}
- *
- * @throws IOException thrown if the {@link Screencast} is not found
- */
- synchronized void addScreencast(Test test, Screencast screencast) throws IOException {
- for (ExtentReporter r : reporterList) {
- r.onScreencastAdded(test, screencast);
- }
- }
-
- /**
- * Returns the context of author with the list of tests for each
- *
- * @return a {@link TestAttributeTestContextProvider} object
- */
- protected TestAttributeTestContextProvider getAuthorContextInfo() {
- return authorContext;
- }
-
- /**
- * Updates the status of the report or build
- *
- * @param status a {@link Status}
- */
- private void updateReportStatus(Status status) {
- int statusIndex = Status.getStatusHierarchy().indexOf(status);
- int reportStatusIndex = Status.getStatusHierarchy().indexOf(reportStatus);
-
- reportStatus = statusIndex < reportStatusIndex
- ? status
- : reportStatus;
- }
-
- /**
- * Ends the test
- *
- * @param test a {@link Test} object
- */
- private void endTest(Test test) {
- test.end();
- updateReportStatus(test.getStatus());
- }
-
- /**
- * Collects and updates all run information and notifies all reporters. Depending upon the
- * type of reporter, additional events can occur such as:
- *
- *
- *
A file written to disk (eg. case of {@link BasicFileReporter}
- *
A database being updated (eg. case of KlovReporter)
- *
- */
- protected synchronized void flush() {
- collectRunInfo();
- notifyReporters();
- }
-
- /**
- * Collects run information from all tests for assigned {@link Category}, {@link Author},
- * Exception, Nodes. This also ends and updates all internal test information and
- * refreshes {@link ReportStatusStats} and the distinct list of {@link Status}
- */
- private synchronized void collectRunInfo() {
- if (testList == null || testList.isEmpty())
- return;
-
- reportEndDate = Calendar.getInstance().getTime();
-
- refreshReportEntities();
-
- for (Test test : testList) {
- endTest(test);
- test.setUseManualConfiguration(getAllowManualConfig());
- if (test.hasCategory()) {
- test.getCategoryContext().getAll()
- .forEach(x -> categoryContext.setAttributeContext((Category)x, test));
- }
- if (test.hasAuthor()) {
- test.getAuthorContext().getAll()
- .forEach(x -> authorContext.setAttributeContext((Author)x, test));
- }
- if (test.hasDevice()) {
- test.getDeviceContext().getAll()
- .forEach(x -> deviceContext.setAttributeContext((Device)x, test));
- }
- if (test.hasException()) {
- test.getExceptionInfoList()
- .forEach(x -> exceptionContextBuilder.setExceptionContext(x, test));
- }
- if (test.hasChildren()) {
- for (Test node : test.getNodeContext().getAll()) {
- copyNodeAttributeAndRunTimeInfoToAttributeContexts(node);
- node.setUseManualConfiguration(getAllowManualConfig());
- }
- }
- }
-
- updateReportStartTimeForManualConfigurationSetting();
- }
-
- /**
- * In case where manual configuration is used, calculate the correct timestamps based upon
- * the timestamps assigned to tests
- */
- private void updateReportStartTimeForManualConfigurationSetting() {
- if (getAllowManualConfig() && !testList.isEmpty()) {
- Date minDate = testList.stream()
- .map(t -> t.getStartTime())
- .min(Date::compareTo)
- .get();
- Date maxDate = testList.stream()
- .map(t -> t.getEndTime())
- .max(Date::compareTo)
- .get();
- reportStartDate = reportStartDate.getTime() > minDate.getTime() ? minDate : reportStartDate;
- reportEndDate = reportEndDate.getTime() < maxDate.getTime() ? maxDate : reportEndDate;
- }
- }
-
- /**
- * Traverse all nodes and refresh {@link Category}, {@link Author}, Exception and Node context
- * information
- *
- * @param node a {@link Test} node
- */
- private void copyNodeAttributeAndRunTimeInfoToAttributeContexts(Test node) {
- if (node.hasCategory()) {
- node.getCategoryContext().getAll()
- .forEach(x -> categoryContext.setAttributeContext((Category)x, node));
- }
- if (node.hasAuthor()) {
- node.getAuthorContext().getAll()
- .forEach(x -> authorContext.setAttributeContext((Author)x, node));
- }
- if (node.hasDevice()) {
- node.getDeviceContext().getAll()
- .forEach(x -> deviceContext.setAttributeContext((Device)x, node));
- }
- if (node.hasException()) {
- node.getExceptionInfoList()
- .forEach(x -> exceptionContextBuilder.setExceptionContext(x, node));
- }
- if (node.hasChildren()) {
- node.getNodeContext().getAll()
- .forEach(this::copyNodeAttributeAndRunTimeInfoToAttributeContexts);
- }
- }
-
- /**
- * Notify all reporters with complete run information
- */
- private synchronized void notifyReporters() {
- if (!testList.isEmpty() && testList.get(0).isBehaviorDrivenType()) {
- strategy = AnalysisStrategy.BDD;
- }
- ReportAggregates reportAggregates = new ReportAggregatesBuilder()
- .setAuthorContext(authorContext)
- .setCategoryContext(categoryContext)
- .setDeviceContext(deviceContext)
- .setExceptionContext(exceptionContextBuilder)
- .setReportStatusStats(stats)
- .setStatusList(statusList)
- .setSystemAttributeContext(systemAttributeContext)
- .setTestList(testList)
- .setTestRunnerLogs(testRunnerLogs)
- .setStartTime(reportStartDate)
- .setEndTime(reportEndDate)
- .build();
- reporterList.forEach(x -> x.setAnalysisStrategy(strategy));
- reporterList.forEach(x -> x.flush(reportAggregates));
- }
-
- /**
- * Ends logging, stops and clears the list of reporters
- */
- protected void end() {
- flush();
- reporterList.forEach(ExtentReporter::stop);
- reporterList.clear();
- }
-
- /**
- * Add a system attribute
- *
- * @param sa a {@link SystemAttribute} object
- */
- protected void setSystemInfo(SystemAttribute sa) {
- systemAttributeContext.setSystemAttribute(sa);
- }
-
- /**
- * Add a test runner log
- *
- * @param log a log event
- */
- protected void setTestRunnerLogs(String log) {
- testRunnerLogs.add(log);
- }
-
- /**
- * Updates the {@link AnalysisStrategy}
- *
- * @param strategy a {@link AnalysisStrategy} object
- */
- protected void setAnalysisStrategy(AnalysisStrategy strategy) {
- this.strategy = strategy;
- stats = new ReportStatusStats(strategy);
- }
-
- /**
- * Setting to allow user driven configuration for test time-stamps
- *
- * @param useManualConfig setting for manual configuration
- */
- protected void setAllowManualConfig(boolean useManualConfig) {
- this.usesManualConfiguration = useManualConfig;
- }
-
- /**
- * Returns the current value of using manual configuration for test time-stamps
- *
- * @return setting for manual configuration
- */
- protected boolean getAllowManualConfig() {
- return usesManualConfiguration;
- }
-
- /**
- * Return the {@link ReportStatusStats} object
- *
- * @return a {@link ReportStatusStats} object
- */
- protected ReportStatusStats getStats() {
- return stats;
- }
-
-}
diff --git a/src/main/java/com/aventstack/extentreports/ExtentReporter.java b/src/main/java/com/aventstack/extentreports/ExtentReporter.java
deleted file mode 100644
index ac5961c..0000000
--- a/src/main/java/com/aventstack/extentreports/ExtentReporter.java
+++ /dev/null
@@ -1,33 +0,0 @@
-package com.aventstack.extentreports;
-
-/**
- * Primary interface implemented by each reporter. This interface implements {@link TestListener} and
- * {@link ReportAggregatesListener} interface to provide additional functionality to each reporter.
- */
-public interface ExtentReporter
- extends TestListener, AnalysisStrategyService {
-
- /**
- * Starts passing run information to the reporter
- */
- void start();
-
- /**
- * Stops the reporter. Ensures no information is passed to the reporter.
- */
- void stop();
-
- /**
- * Write to or update the target source (file, database)
- *
- * @param reportAggregates a {@link ReportAggregates} object
- */
- void flush(ReportAggregates reportAggregates);
-
- /**
- * Get the reporter name
- *
- * @return reporter name
- */
- String getReporterName();
-}
\ No newline at end of file
diff --git a/src/main/java/com/aventstack/extentreports/ExtentReports.java b/src/main/java/com/aventstack/extentreports/ExtentReports.java
index 18e437c..e5f7a77 100644
--- a/src/main/java/com/aventstack/extentreports/ExtentReports.java
+++ b/src/main/java/com/aventstack/extentreports/ExtentReports.java
@@ -1,22 +1,31 @@
package com.aventstack.extentreports;
+import java.io.File;
+import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.Arrays;
import java.util.List;
+import com.aventstack.extentreports.convert.TestModelReportBuilder;
import com.aventstack.extentreports.gherkin.GherkinDialectProvider;
import com.aventstack.extentreports.gherkin.model.IGherkinFormatterModel;
+import com.aventstack.extentreports.model.Media;
+import com.aventstack.extentreports.model.ScreenCapture;
import com.aventstack.extentreports.model.SystemAttribute;
+import com.aventstack.extentreports.reporter.ExtentKlovReporter;
+import com.aventstack.extentreports.reporter.ExtentReporter;
/**
*
- * The ExtentReports report client for starting reporters and building reports. For most applications,
- * you should have one ExtentReports instance for the entire JVM.
+ * The ExtentReports report client for starting reporters and building reports.
+ * For most applications, you should have one ExtentReports instance for the
+ * entire JVM.
*
*
*
- * ExtentReports itself does not build any reports, but allows reporters to access information, which in
- * turn build the said reports. An example of building an HTML report and adding information to ExtentX:
+ * ExtentReports itself does not build any reports, but allows reporters to
+ * access information, which in turn build the said reports. An example of
+ * building an HTML report and adding information to ExtentX:
*
*
*
@@ -32,13 +41,14 @@
*
*
*
- * A few notes:
+ * A few notes:
*
*
*
- *
It is mandatory to call the flush method to ensure information is written to the started
- * reporters.
- *
You can create standard and BDD-style tests using the createTest method
+ *
It is mandatory to call the flush method to ensure
+ * information is written to the started reporters.
+ *
You can create standard and BDD-style tests using the
+ * createTest method
*
*
* @see ExtentTest
@@ -46,358 +56,433 @@
* @see IGherkinFormatterModel
* @see Status
*/
-public class ExtentReports
- extends ExtentObservable {
-
- /**
- * Attach a {@link ExtentReporter} reporter, allowing it to access all started tests, nodes and logs
- *
- *
- * Available reporter types are:
- *
- *
- *
- *
ExtentHtmlReporter provided by artifactId "extent-html-formatter"
- *
ExtentEmailReporter (pro-only) provided by artifactId "extent-email-formatter"
- *
KlovReporter provided by artifactId "extent-klov-reporter"
- *
ConsoleLogger
- *
- *
- * @param reporter {@link ExtentReporter} reporter
- */
- public void attachReporter(ExtentReporter... reporter) {
- Arrays.stream(reporter).forEach(this::register);
- }
-
- /**
- * Returns a list of started reporters
- *
- * @return A list of {@link ExtentReporter}
- */
- public List getStartedReporters() {
- return getReporterCollection();
- }
+public class ExtentReports extends ReportObservable {
- /**
- * Creates a BDD-style test with description representing one of the {@link IGherkinFormatterModel}
- * classes such as:
- *
- *
- *
- * @param type A {@link IGherkinFormatterModel} type
- * @param testName Name of test
- * @param description A short description of the test
- *
- * @return {@link ExtentTest} object
- */
- public synchronized ExtentTest createTest(Class extends IGherkinFormatterModel> type, String testName, String description) {
- ExtentTest t = new ExtentTest(this, type, testName, description);
- applyCommonTestSettings(t);
-
- saveTest(t.getModel());
-
- return t;
- }
-
- /**
- * Creates a BDD-style test representing one of the {@link IGherkinFormatterModel} classes such as:
- *
- *
- *
- * @param type A {@link IGherkinFormatterModel} type
- * @param testName Name of test
- *
- * @return {@link ExtentTest} object
- */
- public synchronized ExtentTest createTest(Class extends IGherkinFormatterModel> type, String testName) {
- return createTest(type, testName, null);
- }
-
- /**
- * Creates a BDD-style test with description using name of the Gherkin model such as:
- *
- *
- *
- * @param gherkinKeyword Name of the {@link GherkinKeyword}
- * @param testName Name of test
- * @param description A short description of the test
- *
- * @return {@link ExtentTest} object
- */
- public synchronized ExtentTest createTest(GherkinKeyword gherkinKeyword, String testName, String description) {
- Class extends IGherkinFormatterModel> clazz = gherkinKeyword.getKeyword().getClass();
- return createTest(clazz, testName, description);
- }
-
- /**
- * Creates a BDD-style test using name of the Gherkin model such as:
- *
- *
- *
- * @param gherkinKeyword Name of the {@link GherkinKeyword}
- * @param testName Name of test
- *
- * @return {@link ExtentTest} object
- */
- public synchronized ExtentTest createTest(GherkinKeyword gherkinKeyword, String testName) {
- return createTest(gherkinKeyword, testName, null);
- }
-
- /**
- * Creates a test with description
- *
- * @param testName Name of test
- * @param description A short test description
- *
- * @return {@link ExtentTest} object
- */
- public synchronized ExtentTest createTest(String testName, String description) {
- ExtentTest t = new ExtentTest(this, testName, description);
- applyCommonTestSettings(t);
-
- saveTest(t.getModel());
-
- return t;
- }
+ private static final String[] IMAGE_PATH_RESOLVER_DIR = new String[] { "target/", "test-output/" };
+
+ /**
+ * Attach a {@link ExtentReporter} reporter, allowing it to access all started
+ * tests, nodes and logs
+ *
+ *
+ * Available reporter types are:
+ *
+ *
+ *
+ *
ExtentHtmlReporter provided by artifactId "extent-html-formatter"
+ *
ExtentEmailReporter (pro-only) provided by artifactId
+ * "extent-email-formatter"
+ *
KlovReporter provided by artifactId "extent-klov-reporter"
+ *
ConsoleLogger
+ *
+ *
+ * @param reporter {@link ExtentReporter} reporter
+ */
+ public void attachReporter(ExtentReporter... reporter) {
+ Arrays.stream(reporter).forEach(this::register);
+ }
+
+ /**
+ * Returns a list of started reporters
+ *
+ * @return A list of {@link ExtentReporter}
+ */
+ public List getStartedReporters() {
+ return getReporterCollection();
+ }
+
+ /**
+ * Creates a BDD-style test with description representing one of the
+ * {@link IGherkinFormatterModel} classes such as:
+ *
+ *
+ *
+ * @param type A {@link IGherkinFormatterModel} type
+ * @param testName Name of test
+ * @param description A short description of the test
+ *
+ * @return {@link ExtentTest} object
+ */
+ public ExtentTest createTest(Class extends IGherkinFormatterModel> type, String testName,
+ String description) {
+ ExtentTest t = new ExtentTest(this, type, testName, description);
+ applyCommonTestSettings(t);
+ saveTest(t.getModel());
+ return t;
+ }
+
+ /**
+ * Creates a BDD-style test representing one of the
+ * {@link IGherkinFormatterModel} classes such as:
+ *
+ *
+ *
+ * @param type A {@link IGherkinFormatterModel} type
+ * @param testName Name of test
+ *
+ * @return {@link ExtentTest} object
+ */
+ public ExtentTest createTest(Class extends IGherkinFormatterModel> type, String testName) {
+ return createTest(type, testName, null);
+ }
+
+ /**
+ * Creates a BDD-style test with description using name of the Gherkin model
+ * such as:
+ *
+ *
+ *
+ * @param gherkinKeyword Name of the {@link GherkinKeyword}
+ * @param testName Name of test
+ * @param description A short description of the test
+ *
+ * @return {@link ExtentTest} object
+ */
+ public ExtentTest createTest(GherkinKeyword gherkinKeyword, String testName, String description) {
+ Class extends IGherkinFormatterModel> clazz = gherkinKeyword.getKeyword().getClass();
+ return createTest(clazz, testName, description);
+ }
+
+ /**
+ * Creates a BDD-style test using name of the Gherkin model such as:
+ *
+ *
- *
- * @param k Name of system variable
- * @param v Value of system variable
- */
- public void setSystemInfo(String k, String v) {
- SystemAttribute sa = new SystemAttribute(k, v);
- super.setSystemInfo(sa);
- }
-
- /**
- * Adds logs from test framework tools to the test-runner logs view (if available in the reporter)
- *
- *
- *
- * @param log Log string from the test runner frameworks such as TestNG or JUnit
- */
- public void setTestRunnerOutput(List log) {
- log.forEach(this::setTestRunnerLogs);
- }
-
- /**
- * Adds logs from test framework tools to the test-runner logs view (if available in the reporter)
- *
- *
- * TestNG usage example:
- *
- *
- *
- * for (String s : Reporter.getOutput()) {
- * extent.setTestRunnerOutput(s);
- * }
- *
- *
- * @param log Log string from the test runner frameworks such as TestNG or JUnit
- */
- public void setTestRunnerOutput(String log) {
- setTestRunnerLogs(log);
- }
-
- /**
- * Use this setting when building post-execution reports, such as from TestNG IReporter.
- * This setting allows setting test with your own time-stamps. With this enabled, Extent
- * does not use time-stamps for tests at the time they were created.
- *
- *
- * If this setting is enabled and time-stamps are not specified explicitly, the time-stamps
- * of test creation are used.
- *
- * @param useManualConfig Set to true if building reports at the end of execution with manual configuration
- */
- public void setReportUsesManualConfiguration(boolean useManualConfig) {
- setAllowManualConfig(useManualConfig);
- }
+ /**
+ * Removes a test
+ *
+ * @param test {@link ExtentTest} object
+ */
+ public void removeTest(ExtentTest test) {
+ super.removeTest(test.getModel());
+ }
+
+ /**
+ * Writes test information from the started reporters to their output view
+ *
+ *
+ *
extent-html-formatter: flush output to HTML file
+ *
extent-klov-reporter: updates MongoDB collections
+ *
extent-email-formatter (pro-only): creates or appends to an HTML
+ * file
+ *
ConsoleLogger: no action taken
+ *
+ */
+ @Override
+ public void flush() {
+ super.flush();
+ }
/**
- * Type of AnalysisStrategy for the reporter. Not all reporters support this setting.
- *
- *
- * There are 2 types of strategies available:
- *
- *
- *
TEST: Shows analysis at the test and step level
- *
SUITE: Shows analysis at the suite, test and step level
- *
- *
- * @param strategy {@link AnalysisStrategy} determines the type of analysis (dashboard)
- * created for the reporter. Not all reporters will support this setting.
- */
- @Override
- public void setAnalysisStrategy(AnalysisStrategy strategy) {
- super.setAnalysisStrategy(strategy);
- }
-
- /**
- * Provides common report configurations
- *
- * @return an instance of {@link ReportConfigurator}
- */
- public ReportConfigurator config() {
- return ReportConfigurator.getInstance();
- }
-
- /**
- * Allows setting the target language for Gherkin keywords.
- *
- *
- * Default setting is "en"
- *
- * @param language A valid dialect from
- * gherkin-languages.json
- *
- * @throws UnsupportedEncodingException Thrown if the language is one of the supported language from
- * gherkin-languages.json
- */
- public void setGherkinDialect(String language) throws UnsupportedEncodingException {
- GherkinDialectProvider.setLanguage(language);
- }
-
- /**
- * Returns an instance of {@link ReportStatusStats} with counts of tests executed
- * by their status (pass, fail, skip etc)
- *
- * @return an instance of {@link ReportStatusStats}
- */
- @Override
- public ReportStatusStats getStats() {
- return super.getStats();
- }
-
-}
+ * Adds any applicable system information to all started reporters
+ *
+ *
+ *
+ * @param k Name of system variable
+ * @param v Value of system variable
+ */
+ public void setSystemInfo(String k, String v) {
+ SystemAttribute sa = new SystemAttribute(k, v);
+ super.setSystemInfo(sa);
+ }
+
+ /**
+ * Adds logs from test framework tools to the test-runner logs view (if
+ * available in the reporter)
+ *
+ *
+ *
+ * @param log Log string from the test runner frameworks such as TestNG or JUnit
+ */
+ public void setTestRunnerOutput(List log) {
+ log.forEach(this::setTestRunnerLogs);
+ }
+
+ /**
+ * Adds logs from test framework tools to the test-runner logs view (if
+ * available in the reporter)
+ *
+ *
+ * TestNG usage example:
+ *
+ *
+ *
+ * for (String s : Reporter.getOutput()) {
+ * extent.setTestRunnerOutput(s);
+ * }
+ *
+ *
+ * @param log Log string from the test runner frameworks such as TestNG or JUnit
+ */
+ public void setTestRunnerOutput(String log) {
+ setTestRunnerLogs(log);
+ }
+
+ /**
+ * Tries to resolve a {@link ScreenCapture} location if the supplied path is not found using
+ * default locations. This can resolve cases where the default path was supplied to be relative
+ * for a FileReporter. If the absolute path is not determined, the supplied will be used.
+ * below paths are used to locate the image:
+ *
+ *
+ *
target/
+ *
test-output//
+ *
+ *
+ * @return {@link ExtentKlovReporter}
+ */
+ public ExtentReports tryResolveMediaPath() {
+ setMediaPathResolveDir(IMAGE_PATH_RESOLVER_DIR);
+ return this;
+ }
+
+ /**
+ * Tries to resolve a {@link ScreenCapture} location if the supplied path is not found using
+ * supplied locations. This can resolve cases where the default path was supplied to be relative
+ * for a FileReporter. If the absolute path is not determined, the supplied will be used.
+ *
+ * @param paths Dirs used to create absolute path of the {@link Media} object
+ *
+ * @return {@link ExtentKlovReporter}
+ */
+ public ExtentReports tryResolveMediaPath(String[] paths) {
+ setMediaPathResolveDir(paths);
+ return this;
+ }
+
+ /**
+ * Creates the internal models by consuming a JSON archive from a previous run
+ * session. This provides the same functionality as available in earlier versions
+ * via appendExisting, with the exception of being accessible by
+ * all reporters instead of just one.
+ *
+ * @param jsonFile The JSON archive file
+ * @throws IOException Exception thrown if the jsonFile is not found
+ */
+ public void createDomainFromJsonArchive(File jsonFile) throws IOException {
+ TestModelReportBuilder modelBuilder = new TestModelReportBuilder();
+ modelBuilder.createDomainFromJsonArchive(this, jsonFile);
+ }
+
+ /**
+ * Creates the internal models by consuming a JSON archive from a previous run
+ * session. This provides the same functionality as available in earlier versions
+ * via appendExisting, with the exception of being accessible by
+ * all reporters instead of just one.
+ *
+ * @param jsonFilePath The JSON archive file
+ * @throws IOException Exception thrown if the jsonFilePath is not found
+ */
+ public void createDomainFromJsonArchive(String jsonFilePath) throws IOException {
+ createDomainFromJsonArchive(new File(jsonFilePath));
+ }
+
+ /**
+ * Use this setting when building post-execution reports, such as from TestNG
+ * IReporter. This setting allows setting test with your own time-stamps. With
+ * this enabled, Extent does not use time-stamps for tests at the time they were
+ * created.
+ *
+ *
+ * If this setting is enabled and time-stamps are not specified explicitly, the
+ * time-stamps of test creation are used.
+ *
+ * @param useManualConfig Set to true if building reports at the end of
+ * execution with manual configuration
+ */
+ public void setReportUsesManualConfiguration(boolean useManualConfig) {
+ setAllowManualConfig(useManualConfig);
+ }
+
+ public Boolean getReportUsesManualConfiguration() {
+ return getAllowManualConfig();
+ }
+
+ /**
+ * Type of AnalysisStrategy for the reporter. Not all reporters support this
+ * setting.
+ *
+ *
+ * There are 2 types of strategies available:
+ *
+ *
+ *
TEST: Shows analysis at the test and step level
+ *
SUITE: Shows analysis at the suite, test and step level
+ *
+ *
+ * @param strategy {@link AnalysisStrategy} determines the type of analysis
+ * (dashboard) created for the reporter. Not all reporters will
+ * support this setting.
+ */
+ @Override
+ public void setAnalysisStrategy(AnalysisStrategy strategy) {
+ super.setAnalysisStrategy(strategy);
+ }
+
+ /**
+ * Provides common report configurations
+ *
+ * @return an instance of {@link ReportConfigurator}
+ */
+ public ReportConfigurator config() {
+ return ReportConfigurator.getInstance();
+ }
+
+ /**
+ * Allows setting the target language for Gherkin keywords.
+ *
+ *
+ * Default setting is "en"
+ *
+ * @param language A valid dialect from gherkin-languages.json
+ *
+ * @throws UnsupportedEncodingException Thrown if the language is one of the
+ * supported language from gherkin-languages.json
+ */
+ public void setGherkinDialect(String language) throws UnsupportedEncodingException {
+ GherkinDialectProvider.setLanguage(language);
+ }
+
+ /**
+ * Returns an instance of {@link ReportStatusStats} with counts of tests
+ * executed by their status (pass, fail, skip etc)
+ *
+ * @return an instance of {@link ReportStatusStats}
+ */
+ @Override
+ public ReportStatusStats getStats() {
+ return super.getStats();
+ }
+
+}
\ No newline at end of file
diff --git a/src/main/java/com/aventstack/extentreports/ExtentTest.java b/src/main/java/com/aventstack/extentreports/ExtentTest.java
index a36e634..d346436 100644
--- a/src/main/java/com/aventstack/extentreports/ExtentTest.java
+++ b/src/main/java/com/aventstack/extentreports/ExtentTest.java
@@ -10,17 +10,16 @@
import com.aventstack.extentreports.model.Category;
import com.aventstack.extentreports.model.Device;
import com.aventstack.extentreports.model.ExceptionInfo;
-import com.aventstack.extentreports.model.IAddsMedia;
import com.aventstack.extentreports.model.Log;
import com.aventstack.extentreports.model.Media;
-import com.aventstack.extentreports.model.MediaType;
import com.aventstack.extentreports.model.ScreenCapture;
-import com.aventstack.extentreports.model.Screencast;
import com.aventstack.extentreports.model.Test;
+import com.aventstack.extentreports.utils.ExceptionUtil;
import com.aventstack.extentreports.utils.StringUtil;
/**
- * Defines a test. You can add logs, snapshots, assign author and categories to a test and its children.
+ * Defines a test. You can add logs, snapshots, assign author and categories to
+ * a test and its children.
*
*
* The below log types will all be logged with Status.PASS:
@@ -37,1182 +36,1189 @@
*
*
*
- *
Tests started with the createTest method are parent-level, always level 0
- *
Tests started with the createNode method are children, always level 1 and greater
+ *
Tests started with the createTest method are parent-level,
+ * always level 0
+ *
Tests started with the createNode method are children,
+ * always level 1 and greater
*
*/
-public class ExtentTest
- implements IAddsMedia, RunResult, Serializable {
-
- private static final long serialVersionUID = 9199820968410788862L;
-
- /**
- * An instance of {@link ExtentReports} to which this {@link ExtentTest} belongs
- */
- private transient ExtentReports extent;
-
- /**
- * Internal model
- */
- private Test test;
-
- /**
- * Creates a BDD style parent test representing one of the {@link IGherkinFormatterModel}
- * classes. This method would ideally be used for creating the parent, ie {@link Feature).
- *
- *
- *
- * @param type A {@link IGherkinFormatterModel} type
- * @param name Name of node
- *
- * @return {@link ExtentTest} object
- */
- public synchronized ExtentTest createNode(Class extends IGherkinFormatterModel> type, String name) {
- return createNode(type, name, null);
- }
-
- /**
- * Creates a BDD-style node with description using name of the Gherkin model such as:
- *
- *
- *
- * @param gherkinKeyword Name of the {@link GherkinKeyword}
- * @param name Name of node
- * @param description A short description
- *
- * @return {@link ExtentTest}
- */
- public synchronized ExtentTest createNode(GherkinKeyword gherkinKeyword, String name, String description) {
- Class extends IGherkinFormatterModel> clazz = gherkinKeyword.getKeyword().getClass();
- return createNode(clazz, name, description);
- }
-
- /**
- * Creates a BDD-style node using name of the Gherkin model such as:
- *
- *
- *
- * @param details Details
- * @param provider A {@link MediaEntityModelProvider} object
- *
- * @return An {@link ExtentTest} object
- */
- public ExtentTest info(String details, MediaEntityModelProvider provider) {
- log(Status.INFO, details, provider);
- return this;
- }
-
- /**
- * Logs an event with Status.INFO with details
- *
- * @param details Details
- *
- * @return {@link ExtentTest} object
- */
- public ExtentTest info(String details) {
- return info(details, null);
- }
-
- /**
- * Logs an Status.INFO event with an exception and a media object:
- * {@link Screencast} or {@link ScreenCapture}
- *
- *
- * Example:
- *
- *
- *
- * Exception exception = new NullPointerException();
+public class ExtentTest implements IAddsMedia, RunResult, Serializable {
+
+ private static final long serialVersionUID = 9199820968410788862L;
+
+ /**
+ * An instance of {@link ExtentReports} to which this {@link ExtentTest} belongs
+ */
+ private transient ExtentReports extent;
+
+ /**
+ * Internal model
+ */
+ private Test test;
+
+ /**
+ * Creates a BDD style parent test representing one of the
+ * {@link IGherkinFormatterModel} classes. This method would ideally be used for
+ * creating the parent, ie {@link Feature).
+ *
+ *
+ *
+ * @param type A {@link IGherkinFormatterModel} type
+ * @param name Name of node
+ *
+ * @return {@link ExtentTest} object
+ */
+ public ExtentTest createNode(Class extends IGherkinFormatterModel> type, String name) {
+ return createNode(type, name, null);
+ }
+
+ /**
+ * Creates a BDD-style node with description using name of the Gherkin model
+ * such as:
+ *
+ *
+ *
+ * @param gherkinKeyword Name of the {@link GherkinKeyword}
+ * @param name Name of node
+ * @param description A short description
+ *
+ * @return {@link ExtentTest}
+ */
+ public ExtentTest createNode(GherkinKeyword gherkinKeyword, String name, String description) {
+ Class extends IGherkinFormatterModel> clazz = gherkinKeyword.getKeyword().getClass();
+ return createNode(clazz, name, description);
+ }
+
+ /**
+ * Creates a BDD-style node using name of the Gherkin model such as:
+ *
+ *
@@ -41,46 +42,46 @@
public class GherkinKeyword {
private static final Logger logger = Logger.getLogger(GherkinKeyword.class.getName());
-
- private Class clazz = IGherkinFormatterModel.class;
- private IGherkinFormatterModel keywordClazz;
-
- public GherkinKeyword(String keyword) throws ClassNotFoundException {
- GherkinDialect dialect = null;
- String apiKeyword = StringUtil.capitalize(keyword.trim());
- String refPath = clazz.getPackage().getName();
-
- try {
- apiKeyword = apiKeyword.equals("*") ? Asterisk.class.getSimpleName() : apiKeyword;
- dialect = GherkinDialectProvider.getDialect();
- if (dialect != null && !dialect.getLanguage().equalsIgnoreCase(GherkinDialectProvider.getDefaultLanguage())) {
- apiKeyword = null;
- Map> keywords = dialect.getKeywords();
-
- for (Entry> key : keywords.entrySet()) {
- boolean keywordLocated = key.getValue()
- .stream()
- .anyMatch(x -> x.trim().equalsIgnoreCase(keyword.trim()));
- if (keywordLocated) {
- apiKeyword = StringUtil.capitalize(key.getKey());
- break;
- }
- }
- }
-
- if (apiKeyword == null) {
- throw new GherkinKeywordNotFoundException("Keyword " + apiKeyword + " cannot be null");
- }
-
- String clazzName = refPath + "." + apiKeyword.replace(" ", "");
- Class> c = Class.forName(clazzName);
- keywordClazz = (IGherkinFormatterModel) c.newInstance();
- } catch (InstantiationException | IllegalAccessException e) {
- logger.log(Level.SEVERE, "", e);
- }
- }
-
- IGherkinFormatterModel getKeyword() {
- return keywordClazz;
- }
-}
+
+ private Class clazz = IGherkinFormatterModel.class;
+ private IGherkinFormatterModel keywordClazz;
+
+ public GherkinKeyword(String keyword) throws ClassNotFoundException {
+ GherkinDialect dialect = null;
+ String apiKeyword = StringUtil.capitalize(keyword.trim());
+ String refPath = clazz.getPackage().getName();
+
+ try {
+ apiKeyword = apiKeyword.equals("*") ? Asterisk.class.getSimpleName() : apiKeyword;
+ dialect = GherkinDialectProvider.getDialect();
+ if (dialect != null
+ && !dialect.getLanguage().equalsIgnoreCase(GherkinDialectProvider.getDefaultLanguage())) {
+ apiKeyword = null;
+ Map> keywords = dialect.getKeywords();
+
+ for (Entry> key : keywords.entrySet()) {
+ boolean keywordLocated = key.getValue().stream()
+ .anyMatch(x -> x.trim().equalsIgnoreCase(keyword.trim()));
+ if (keywordLocated) {
+ apiKeyword = StringUtil.capitalize(key.getKey());
+ break;
+ }
+ }
+ }
+
+ if (apiKeyword == null) {
+ throw new GherkinKeywordNotFoundException("Keyword " + apiKeyword + " cannot be null");
+ }
+
+ String clazzName = refPath + "." + apiKeyword.replace(" ", "");
+ Class> c = Class.forName(clazzName);
+ keywordClazz = (IGherkinFormatterModel) c.newInstance();
+ } catch (InstantiationException | IllegalAccessException e) {
+ logger.log(Level.SEVERE, "", e);
+ }
+ }
+
+ IGherkinFormatterModel getKeyword() {
+ return keywordClazz;
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/aventstack/extentreports/exceptions/GherkinKeywordNotFoundException.java b/src/main/java/com/aventstack/extentreports/GherkinKeywordNotFoundException.java
similarity index 53%
rename from src/main/java/com/aventstack/extentreports/exceptions/GherkinKeywordNotFoundException.java
rename to src/main/java/com/aventstack/extentreports/GherkinKeywordNotFoundException.java
index 2e623a3..198412f 100644
--- a/src/main/java/com/aventstack/extentreports/exceptions/GherkinKeywordNotFoundException.java
+++ b/src/main/java/com/aventstack/extentreports/GherkinKeywordNotFoundException.java
@@ -1,12 +1,11 @@
-package com.aventstack.extentreports.exceptions;
+package com.aventstack.extentreports;
-public class GherkinKeywordNotFoundException
- extends ClassNotFoundException {
+public class GherkinKeywordNotFoundException extends ClassNotFoundException {
private static final long serialVersionUID = 3140022717738862603L;
public GherkinKeywordNotFoundException(String message) {
super(message);
}
-
-}
+
+}
\ No newline at end of file
diff --git a/src/main/java/com/aventstack/extentreports/IAddsMedia.java b/src/main/java/com/aventstack/extentreports/IAddsMedia.java
new file mode 100644
index 0000000..daff630
--- /dev/null
+++ b/src/main/java/com/aventstack/extentreports/IAddsMedia.java
@@ -0,0 +1,55 @@
+package com.aventstack.extentreports;
+
+import java.io.IOException;
+
+public interface IAddsMedia {
+
+ /**
+ * Adds a snapshot to the test or log with title
+ *
+ * @param mediaPath Image path
+ * @param title Image title
+ *
+ * @return Object this method is called from, generally
+ * {@link com.aventstack.extentreports.ExtentTest} or {@link com.aventstack.extentreports.model.Log}
+ *
+ * @throws IOException thrown if the imagePath of image is not
+ * found
+ */
+ T addScreenCaptureFromPath(String mediaPath, String title) throws IOException;
+
+ /**
+ * Adds a snapshot to test or log
+ *
+ * @param mediaPath Image path
+ *
+ * @return Object this method is called from, generally
+ * {@link com.aventstack.extentreports.ExtentTest} or {@link com.aventstack.extentreports.model.Log}
+ *
+ * @throws IOException thrown if the imagePath of image is not
+ * found
+ */
+ T addScreenCaptureFromPath(String mediaPath) throws IOException;
+
+ /**
+ * Adds a base64 screenshot
+ *
+ * @param base64 base64 string
+ * @param title Image title
+ *
+ * @return Object this method is called from, generally
+ * {@link com.aventstack.extentreports.ExtentTest} or {@link com.aventstack.extentreports.model.Log}
+ */
+ T addScreenCaptureFromBase64String(String base64, String title);
+
+ /**
+ * Adds a base64 screenshot
+ *
+ * @param base64 base64 string
+ *
+ * @return Object this method is called from, generally
+ * {@link com.aventstack.extentreports.ExtentTest} or {@link com.aventstack.extentreports.model.Log}
+ */
+ T addScreenCaptureFromBase64String(String base64);
+
+}
\ No newline at end of file
diff --git a/src/main/java/com/aventstack/extentreports/AnalysisStrategyService.java b/src/main/java/com/aventstack/extentreports/IAnalysisStrategyMethod.java
similarity index 83%
rename from src/main/java/com/aventstack/extentreports/AnalysisStrategyService.java
rename to src/main/java/com/aventstack/extentreports/IAnalysisStrategyMethod.java
index c89664f..4a92a99 100644
--- a/src/main/java/com/aventstack/extentreports/AnalysisStrategyService.java
+++ b/src/main/java/com/aventstack/extentreports/IAnalysisStrategyMethod.java
@@ -4,10 +4,10 @@
* Marker interface for a class that uses an {@link AnalysisStrategy}
*
*/
-public interface AnalysisStrategyService {
+public interface IAnalysisStrategyMethod {
void setAnalysisStrategy(AnalysisStrategy strategy);
AnalysisStrategy getAnalysisStrategy();
-}
+}
\ No newline at end of file
diff --git a/src/main/java/com/aventstack/extentreports/exceptions/InvalidAnalysisStrategyException.java b/src/main/java/com/aventstack/extentreports/InvalidAnalysisStrategyException.java
similarity index 81%
rename from src/main/java/com/aventstack/extentreports/exceptions/InvalidAnalysisStrategyException.java
rename to src/main/java/com/aventstack/extentreports/InvalidAnalysisStrategyException.java
index dabf365..4ab1c81 100644
--- a/src/main/java/com/aventstack/extentreports/exceptions/InvalidAnalysisStrategyException.java
+++ b/src/main/java/com/aventstack/extentreports/InvalidAnalysisStrategyException.java
@@ -1,4 +1,4 @@
-package com.aventstack.extentreports.exceptions;
+package com.aventstack.extentreports;
public class InvalidAnalysisStrategyException extends IllegalArgumentException {
@@ -7,5 +7,5 @@ public class InvalidAnalysisStrategyException extends IllegalArgumentException {
public InvalidAnalysisStrategyException(String message) {
super(message);
}
-
-}
+
+}
\ No newline at end of file
diff --git a/src/main/java/com/aventstack/extentreports/MediaEntityBuilder.java b/src/main/java/com/aventstack/extentreports/MediaEntityBuilder.java
index 7c11ca6..e008747 100644
--- a/src/main/java/com/aventstack/extentreports/MediaEntityBuilder.java
+++ b/src/main/java/com/aventstack/extentreports/MediaEntityBuilder.java
@@ -3,7 +3,6 @@
import java.io.IOException;
import com.aventstack.extentreports.model.Media;
-import com.aventstack.extentreports.model.MediaType;
import com.aventstack.extentreports.model.ScreenCapture;
/**
@@ -13,55 +12,59 @@
public class MediaEntityBuilder {
private static ThreadLocal media = new ThreadLocal<>();
-
+
private static class MediaBuilderInstance {
- static final MediaEntityBuilder INSTANCE = new MediaEntityBuilder();
-
- private MediaBuilderInstance() { }
- }
-
- private MediaEntityBuilder() { }
-
- private static synchronized MediaEntityBuilder getInstance() {
- return MediaBuilderInstance.INSTANCE;
- }
-
+ static final MediaEntityBuilder INSTANCE = new MediaEntityBuilder();
+
+ private MediaBuilderInstance() {
+ }
+ }
+
+ private MediaEntityBuilder() {
+ }
+
+ private static synchronized MediaEntityBuilder getInstance() {
+ return MediaBuilderInstance.INSTANCE;
+ }
+
public MediaEntityModelProvider build() {
return new MediaEntityModelProvider(media.get());
}
-
- public static synchronized MediaEntityBuilder createScreenCaptureFromPath(String path, String title) throws IOException {
- if (path == null || path.isEmpty())
- throw new IOException("ScreenCapture path cannot be null or empty.");
-
- return createScreenCapture(path, title, false);
- }
-
- public static synchronized MediaEntityBuilder createScreenCaptureFromPath(String path) throws IOException {
- return createScreenCaptureFromPath(path, null);
- }
-
- public static synchronized MediaEntityBuilder createScreenCaptureFromBase64String(String base64String) throws IOException {
- if (base64String == null || base64String.trim().equals(""))
- throw new IOException("Base64 string cannot be null or empty.");
-
- return createScreenCapture(base64String, null, true);
- }
-
- private static synchronized MediaEntityBuilder createScreenCapture(String pathOrBase64String, String title, boolean isBase64String) {
- ScreenCapture sc = new ScreenCapture();
- sc.setMediaType(MediaType.IMG);
- if (isBase64String)
- sc.setBase64String(pathOrBase64String);
- else
- sc.setPath(pathOrBase64String);
-
- if (title != null)
- sc.setName(title);
-
- media.set(sc);
-
- return getInstance();
- }
-
-}
+
+ public static synchronized MediaEntityBuilder createScreenCaptureFromPath(String path, String title)
+ throws IOException {
+ if (path == null || path.isEmpty())
+ throw new IOException("ScreenCapture path cannot be null or empty.");
+
+ return createScreenCapture(path, title, false);
+ }
+
+ public static synchronized MediaEntityBuilder createScreenCaptureFromPath(String path) throws IOException {
+ return createScreenCaptureFromPath(path, null);
+ }
+
+ public static synchronized MediaEntityBuilder createScreenCaptureFromBase64String(String base64String)
+ throws IOException {
+ if (base64String == null || base64String.trim().equals(""))
+ throw new IOException("Base64 string cannot be null or empty.");
+
+ return createScreenCapture(base64String, null, true);
+ }
+
+ private static synchronized MediaEntityBuilder createScreenCapture(String pathOrBase64String, String title,
+ boolean isBase64String) {
+ ScreenCapture sc = new ScreenCapture();
+ if (isBase64String)
+ sc.setBase64String(pathOrBase64String);
+ else
+ sc.setPath(pathOrBase64String);
+
+ if (title != null)
+ sc.setName(title);
+
+ media.set(sc);
+
+ return getInstance();
+ }
+
+}
\ No newline at end of file
diff --git a/src/main/java/com/aventstack/extentreports/MediaEntityModelProvider.java b/src/main/java/com/aventstack/extentreports/MediaEntityModelProvider.java
index 3b2f290..ef13f46 100644
--- a/src/main/java/com/aventstack/extentreports/MediaEntityModelProvider.java
+++ b/src/main/java/com/aventstack/extentreports/MediaEntityModelProvider.java
@@ -2,10 +2,6 @@
import com.aventstack.extentreports.model.Media;
-/**
- * Media singleton
- *
- */
public class MediaEntityModelProvider {
private Media m;
@@ -18,4 +14,4 @@ public Media getMedia() {
return m;
}
-}
+}
\ No newline at end of file
diff --git a/src/main/java/com/aventstack/extentreports/ReportAggregates.java b/src/main/java/com/aventstack/extentreports/ReportAggregates.java
index de16347..e1558f2 100644
--- a/src/main/java/com/aventstack/extentreports/ReportAggregates.java
+++ b/src/main/java/com/aventstack/extentreports/ReportAggregates.java
@@ -1,5 +1,6 @@
package com.aventstack.extentreports;
+import java.util.Collection;
import java.util.Date;
import java.util.List;
@@ -7,6 +8,9 @@
import com.aventstack.extentreports.model.Category;
import com.aventstack.extentreports.model.Device;
import com.aventstack.extentreports.model.Test;
+import com.aventstack.extentreports.model.context.ExceptionTestContextStore;
+import com.aventstack.extentreports.model.context.SystemAttributeContext;
+import com.aventstack.extentreports.model.context.TestAttributeTestContextStore;
/**
* Aggregator for report elements and collections
@@ -16,16 +20,16 @@ public class ReportAggregates {
private List testList;
private List testRunnerLogs;
- private TestAttributeTestContextProvider categoryContext;
- private TestAttributeTestContextProvider authorContext;
- private TestAttributeTestContextProvider deviceContext;
- private ExceptionTestContextImpl exceptionContext;
+ private TestAttributeTestContextStore categoryContext;
+ private TestAttributeTestContextStore authorContext;
+ private TestAttributeTestContextStore deviceContext;
+ private ExceptionTestContextStore exceptionContext;
private SystemAttributeContext systemAttributeContext;
private ReportStatusStats reportStatusStats;
- private List statusList;
+ private Collection statusCollection;
private Date startTime;
private Date endTime;
-
+
public Date getStartTime() {
return startTime;
}
@@ -43,7 +47,7 @@ public void setEndTime(Date endTime) {
}
public Status getStatus() {
- return Status.getHighestStatus(getStatusList());
+ return Status.getHighestStatus(getStatusCollection());
}
public List getTestList() {
@@ -62,35 +66,35 @@ public void setTestRunnerLogs(List testRunnerLogs) {
this.testRunnerLogs = testRunnerLogs;
}
- public TestAttributeTestContextProvider getCategoryContext() {
+ public TestAttributeTestContextStore getCategoryContext() {
return categoryContext;
}
- public void setCategoryContext(TestAttributeTestContextProvider categoryContext) {
+ public void setCategoryContext(TestAttributeTestContextStore categoryContext) {
this.categoryContext = categoryContext;
}
- public TestAttributeTestContextProvider getAuthorContext() {
+ public TestAttributeTestContextStore getAuthorContext() {
return authorContext;
}
- public void setAuthorContext(TestAttributeTestContextProvider authorContext) {
+ public void setAuthorContext(TestAttributeTestContextStore authorContext) {
this.authorContext = authorContext;
}
- public TestAttributeTestContextProvider getDeviceContext() {
+ public TestAttributeTestContextStore getDeviceContext() {
return deviceContext;
}
- public void setDeviceContext(TestAttributeTestContextProvider deviceContext) {
+ public void setDeviceContext(TestAttributeTestContextStore deviceContext) {
this.deviceContext = deviceContext;
}
- public ExceptionTestContextImpl getExceptionContext() {
+ public ExceptionTestContextStore getExceptionContext() {
return exceptionContext;
}
- public void setExceptionContext(ExceptionTestContextImpl exceptionContext) {
+ public void setExceptionContext(ExceptionTestContextStore exceptionContext) {
this.exceptionContext = exceptionContext;
}
@@ -110,12 +114,12 @@ public void setReportStatusStats(ReportStatusStats reportStatusStats) {
this.reportStatusStats = reportStatusStats;
}
- public List getStatusList() {
- return statusList;
+ public Collection getStatusCollection() {
+ return statusCollection;
}
- public void setStatusList(List statusList) {
- this.statusList = statusList;
+ public void setStatusCollection(Collection statusCollection) {
+ this.statusCollection = statusCollection;
}
-}
+}
\ No newline at end of file
diff --git a/src/main/java/com/aventstack/extentreports/ReportAggregatesBuilder.java b/src/main/java/com/aventstack/extentreports/ReportAggregatesBuilder.java
index d2e7084..bea527a 100644
--- a/src/main/java/com/aventstack/extentreports/ReportAggregatesBuilder.java
+++ b/src/main/java/com/aventstack/extentreports/ReportAggregatesBuilder.java
@@ -1,5 +1,6 @@
package com.aventstack.extentreports;
+import java.util.Collection;
import java.util.Date;
import java.util.List;
@@ -7,6 +8,9 @@
import com.aventstack.extentreports.model.Category;
import com.aventstack.extentreports.model.Device;
import com.aventstack.extentreports.model.Test;
+import com.aventstack.extentreports.model.context.ExceptionTestContextStore;
+import com.aventstack.extentreports.model.context.SystemAttributeContext;
+import com.aventstack.extentreports.model.context.TestAttributeTestContextStore;
/**
* Builds {@link ReportAggregates}
@@ -16,29 +20,29 @@ public class ReportAggregatesBuilder {
private List testList;
private List testRunnerLogs;
- private TestAttributeTestContextProvider categoryContext;
- private TestAttributeTestContextProvider authorContext;
- private TestAttributeTestContextProvider deviceContext;
- private ExceptionTestContextImpl exceptionContext;
+ private TestAttributeTestContextStore categoryContext;
+ private TestAttributeTestContextStore authorContext;
+ private TestAttributeTestContextStore deviceContext;
+ private ExceptionTestContextStore exceptionContext;
private SystemAttributeContext systemAttributeContext;
private ReportStatusStats reportStatusStats;
- private List statusList;
+ private Collection statusCollection;
private Date startTime;
private Date endTime;
-
+
public ReportAggregates build() {
- ReportAggregates aggregates = new ReportAggregates();
- aggregates.setTestList(testList);
- aggregates.setTestRunnerLogs(testRunnerLogs);
- aggregates.setCategoryContext(categoryContext);
- aggregates.setAuthorContext(authorContext);
- aggregates.setDeviceContext(deviceContext);
- aggregates.setExceptionContext(exceptionContext);
- aggregates.setSystemAttributeContext(systemAttributeContext);
- aggregates.setReportStatusStats(reportStatusStats);
- aggregates.setStatusList(statusList);
- aggregates.setStartTime(startTime);
- aggregates.setEndTime(endTime);
+ ReportAggregates aggregates = new ReportAggregates();
+ aggregates.setTestList(testList);
+ aggregates.setTestRunnerLogs(testRunnerLogs);
+ aggregates.setCategoryContext(categoryContext);
+ aggregates.setAuthorContext(authorContext);
+ aggregates.setDeviceContext(deviceContext);
+ aggregates.setExceptionContext(exceptionContext);
+ aggregates.setSystemAttributeContext(systemAttributeContext);
+ aggregates.setReportStatusStats(reportStatusStats);
+ aggregates.setStatusCollection(statusCollection);
+ aggregates.setStartTime(startTime);
+ aggregates.setEndTime(endTime);
return aggregates;
}
@@ -52,22 +56,22 @@ public ReportAggregatesBuilder setTestRunnerLogs(List testRunnerLogs) {
return this;
}
- public ReportAggregatesBuilder setCategoryContext(TestAttributeTestContextProvider categoryContext) {
+ public ReportAggregatesBuilder setCategoryContext(TestAttributeTestContextStore categoryContext) {
this.categoryContext = categoryContext;
return this;
}
- public ReportAggregatesBuilder setAuthorContext(TestAttributeTestContextProvider authorContext) {
+ public ReportAggregatesBuilder setAuthorContext(TestAttributeTestContextStore authorContext) {
this.authorContext = authorContext;
return this;
}
- public ReportAggregatesBuilder setDeviceContext(TestAttributeTestContextProvider deviceContext) {
+ public ReportAggregatesBuilder setDeviceContext(TestAttributeTestContextStore deviceContext) {
this.deviceContext = deviceContext;
return this;
}
- public ReportAggregatesBuilder setExceptionContext(ExceptionTestContextImpl exceptionContext) {
+ public ReportAggregatesBuilder setExceptionContext(ExceptionTestContextStore exceptionContext) {
this.exceptionContext = exceptionContext;
return this;
}
@@ -82,19 +86,19 @@ public ReportAggregatesBuilder setReportStatusStats(ReportStatusStats reportStat
return this;
}
- public ReportAggregatesBuilder setStatusList(List statusList) {
- this.statusList = statusList;
+ public ReportAggregatesBuilder setStatusCollection(Collection statusCollection) {
+ this.statusCollection = statusCollection;
+ return this;
+ }
+
+ public ReportAggregatesBuilder setStartTime(Date startTime) {
+ this.startTime = startTime;
+ return this;
+ }
+
+ public ReportAggregatesBuilder setEndTime(Date endTime) {
+ this.endTime = endTime;
return this;
}
- public ReportAggregatesBuilder setStartTime(Date startTime) {
- this.startTime = startTime;
- return this;
- }
-
- public ReportAggregatesBuilder setEndTime(Date endTime) {
- this.endTime = endTime;
- return this;
- }
-
-}
+}
\ No newline at end of file
diff --git a/src/main/java/com/aventstack/extentreports/ReportAggregatesListener.java b/src/main/java/com/aventstack/extentreports/ReportAggregatesListener.java
index 6a6319f..a49863c 100644
--- a/src/main/java/com/aventstack/extentreports/ReportAggregatesListener.java
+++ b/src/main/java/com/aventstack/extentreports/ReportAggregatesListener.java
@@ -6,88 +6,97 @@
import com.aventstack.extentreports.model.Category;
import com.aventstack.extentreports.model.Device;
import com.aventstack.extentreports.model.Test;
+import com.aventstack.extentreports.model.context.ExceptionTestContextStore;
+import com.aventstack.extentreports.model.context.SystemAttributeContext;
+import com.aventstack.extentreports.model.context.TestAttributeTestContextStore;
/**
- * Allows sharing of aggregates/collections to be shared with the started reporter. A few examples
- * of these collections include:
+ * Allows sharing of aggregates/collections to be shared with the started
+ * reporter. A few examples of these collections include:
*
*
- *
Category context - list of all categories and associated tests
- *
Exception context - list of all exceptions and associated tests
- *
Complete list of started tests
- *
System information
+ *
Category context - list of all categories and associated tests
+ *
Exception context - list of all exceptions and associated tests
+ *
Complete list of started tests
+ *
System information
*
*/
public interface ReportAggregatesListener {
-
- /**
- * Allows sharing the complete list of tests with the reporter
- *
- * @param testList list of all tests created by {@link ExtentReports}
- */
- void setTestList(List testList);
-
- /**
- * Passes the complete list of logs to the reporter
- *
- * @param logs testrunner logs
- */
- void setTestRunnerLogs(List logs);
-
- /**
- * Allows sharing the complete list of category and associated tests with the reporter
- *
- * @param categoryContext collection containing categories and all associated tests
- */
- void setCategoryContextInfo(TestAttributeTestContextProvider categoryContext);
- /**
- * Allows sharing the complete list of author and associated tests with the reporter
- *
- * @param authorContext collection containing author and all associated tests
- */
- void setAuthorContextInfo(TestAttributeTestContextProvider authorContext);
-
- /**
- * Allows sharing the complete list of device and associated tests with the reporter
- *
- * @param deviceContext collection containing devices and all associated tests
- */
- void setDeviceContextInfo(TestAttributeTestContextProvider deviceContext);
-
-
- /**
- * Allows sharing the complete list of exceptions and associated tests with the reporter
- *
- * @param exceptionContext collection containing exception and all associated tests
- */
- void setExceptionContextInfo(ExceptionTestContextImpl exceptionContext);
-
- /**
- * Passes all system information to the reporter
- *
- * @param systemAttributeContext system information
- */
- void setSystemAttributeContext(SystemAttributeContext systemAttributeContext);
-
- /**
- * Report Status stats of the run session for all possible levels:
- *
- *
- *
Features/Tests
- *
Scenarios/Logs
- *
Steps
- *
- *
- * @param sc {@link ReportStatusStats} represents stats of each hierarchical level of test/event
- */
- void setReportStatusStats(ReportStatusStats sc);
-
- /**
- * A distinct list of status assigned to tests
- *
- * @param statusList a distinct list of {@link Status}
- */
- void setStatusList(List statusList);
-
-}
+ /**
+ * Allows sharing the complete list of tests with the reporter
+ *
+ * @param testList list of all tests created by {@link ExtentReports}
+ */
+ void setTestList(List testList);
+
+ /**
+ * Passes the complete list of logs to the reporter
+ *
+ * @param logs testrunner logs
+ */
+ void setTestRunnerLogs(List logs);
+
+ /**
+ * Allows sharing the complete list of category and associated tests with the
+ * reporter
+ *
+ * @param categoryContext collection containing categories and all associated
+ * tests
+ */
+ void setCategoryContextInfo(TestAttributeTestContextStore categoryContext);
+
+ /**
+ * Allows sharing the complete list of author and associated tests with the
+ * reporter
+ *
+ * @param authorContext collection containing author and all associated tests
+ */
+ void setAuthorContextInfo(TestAttributeTestContextStore authorContext);
+
+ /**
+ * Allows sharing the complete list of device and associated tests with the
+ * reporter
+ *
+ * @param deviceContext collection containing devices and all associated tests
+ */
+ void setDeviceContextInfo(TestAttributeTestContextStore deviceContext);
+
+ /**
+ * Allows sharing the complete list of exceptions and associated tests with the
+ * reporter
+ *
+ * @param exceptionContext collection containing exception and all associated
+ * tests
+ */
+ void setExceptionContextInfo(ExceptionTestContextStore exceptionContext);
+
+ /**
+ * Passes all system information to the reporter
+ *
+ * @param systemAttributeContext system information
+ */
+ void setSystemAttributeContext(SystemAttributeContext systemAttributeContext);
+
+ /**
+ * Report Status stats of the run session for all possible levels:
+ *
+ *
+ *
Features/Tests
+ *
Scenarios/Logs
+ *
Steps
+ *
+ *
+ * @param sc {@link ReportStatusStats} represents stats of each hierarchical
+ * level of test/event
+ */
+ void setReportStatusStats(ReportStatusStats sc);
+
+ /**
+ * A distinct list of status assigned to tests
+ *
+ * @param statusList a distinct list of {@link Status}
+ */
+ void setStatusList(List statusList);
+
+}
\ No newline at end of file
diff --git a/src/main/java/com/aventstack/extentreports/ReportConfigurator.java b/src/main/java/com/aventstack/extentreports/ReportConfigurator.java
index 6443523..3469eaf 100644
--- a/src/main/java/com/aventstack/extentreports/ReportConfigurator.java
+++ b/src/main/java/com/aventstack/extentreports/ReportConfigurator.java
@@ -2,20 +2,22 @@
public class ReportConfigurator {
- private static class ReportConfiguratorInstance {
- static final ReportConfigurator INSTANCE = new ReportConfigurator();
-
- private ReportConfiguratorInstance() { }
- }
+ private static class ReportConfiguratorInstance {
+ static final ReportConfigurator INSTANCE = new ReportConfigurator();
- private ReportConfigurator() { }
-
- public static ReportConfigurator getInstance() {
- return ReportConfiguratorInstance.INSTANCE;
- }
+ private ReportConfiguratorInstance() {
+ }
+ }
+
+ private ReportConfigurator() {
+ }
+
+ public static ReportConfigurator getInstance() {
+ return ReportConfiguratorInstance.INSTANCE;
+ }
+
+ public StatusConfigurator statusConfigurator() {
+ return StatusConfigurator.getInstance();
+ }
- public StatusConfigurator statusConfigurator() {
- return StatusConfigurator.getInstance();
- }
-
}
\ No newline at end of file
diff --git a/src/main/java/com/aventstack/extentreports/ReportObservable.java b/src/main/java/com/aventstack/extentreports/ReportObservable.java
new file mode 100644
index 0000000..f523429
--- /dev/null
+++ b/src/main/java/com/aventstack/extentreports/ReportObservable.java
@@ -0,0 +1,597 @@
+package com.aventstack.extentreports;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
+
+import com.aventstack.extentreports.model.Author;
+import com.aventstack.extentreports.model.Category;
+import com.aventstack.extentreports.model.Device;
+import com.aventstack.extentreports.model.Log;
+import com.aventstack.extentreports.model.ScreenCapture;
+import com.aventstack.extentreports.model.SystemAttribute;
+import com.aventstack.extentreports.model.Test;
+import com.aventstack.extentreports.model.context.ExceptionTestContextStore;
+import com.aventstack.extentreports.model.context.SystemAttributeContext;
+import com.aventstack.extentreports.model.context.TestAttributeTestContextStore;
+import com.aventstack.extentreports.model.context.helpers.TestRemover;
+import com.aventstack.extentreports.model.service.ScreenCaptureService;
+import com.aventstack.extentreports.model.service.TestService;
+import com.aventstack.extentreports.reporter.BasicFileReporter;
+import com.aventstack.extentreports.reporter.ExtentReporter;
+
+abstract class ReportObservable implements ReportService {
+
+ /**
+ * The current AnalysisStrategy for the run session. This decides the technique
+ * used to count the test status at differing levels. For example, for a BDD
+ * style report, the levels to be calculated are Feature, Scenario and Step (3
+ * levels). For a generic, non-BDD style report, levels can be dynamic. For a
+ * non-BDD style report, levels typically consist of:
+ *
+ *
+ * 2 levels: Test, the leaf-node
+ * Test
+ * - Node
+ * -- Leaf Node
+ * --- Event
+ *
+ */
+ private AnalysisStrategy strategy = AnalysisStrategy.TEST;
+
+ /**
+ * Use this setting when building post-execution reports, such as from TestNG
+ * IReporter. This setting allows setting test with your own variables and
+ * prevent update by Extent. As of today, with this enabled, Extent does not use
+ * time-stamps for tests at the time they were created
+ */
+ private boolean usesManualConfiguration = false;
+
+ /**
+ * The status of the entire report or build
+ */
+ private Status reportStatus = Status.PASS;
+
+ /**
+ * Time the report or build was started
+ */
+ private Date reportStartDate = Calendar.getInstance().getTime();
+
+ /**
+ * Time the report or build ended. This value is updated everytime
+ * flush is called
+ */
+ private Date reportEndDate;
+
+ /**
+ * A collection of tests arranged by category
+ */
+ private TestAttributeTestContextStore categoryContext = new TestAttributeTestContextStore<>();
+
+ /**
+ * A collection of tests arranged by author
+ */
+ private TestAttributeTestContextStore authorContext = new TestAttributeTestContextStore<>();
+
+ /**
+ * A collection of tests arranged by author
+ */
+ private TestAttributeTestContextStore deviceContext = new TestAttributeTestContextStore<>();
+
+ /**
+ * A collection of tests arranged by exception
+ */
+ private ExceptionTestContextStore exceptionContext = new ExceptionTestContextStore();
+
+ /**
+ * A context of all system or environment variables
+ */
+ private SystemAttributeContext systemAttributeContext = new SystemAttributeContext();
+
+ /**
+ * A list of all {@link ExtentReporter} reporters started by the
+ * attachReporter method
+ */
+ private List reporterList = new ArrayList<>();
+
+ /**
+ * Any logs added by to the test runner can be added to Extent
+ *
+ *
+ * TestNG Example:
+ *
+ *
+ * Setting logs with TestNG:
+ *
+ *
+ * Reporter.log("hello world")
+ *
+ *
+ *
+ * Informing Extent of any logs added:
+ *
+ *
+ * for (String s : Reporter.getOutput()) {
+ * extent.setTestRunnerOutput(s);
+ * }
+ *
+ */
+ private List testRunnerLogs = new ArrayList<>();
+
+ /**
+ * A list of all tests created
+ */
+ private List testList = new ArrayList<>();
+
+ /**
+ * Instance of {@link ReportStatusStats}
+ */
+ private ReportStatusStats stats = new ReportStatusStats(strategy);
+
+ /**
+ * A unique collection of statuses tests are marked with
+ *
+ *
+ * Consider a report having 10 tests:
+ *
+ *
+ *
Test1: PASS
+ *
Test2: PASS
+ *
Test3: PASS
+ *
Test4: SKIP
+ *
Test5: SKIP
+ *
Test6: FAIL
+ *
Test7: PASS
+ *
Test8: PASS
+ *
Test9: FAIL
+ *
Test10: PASS
+ *
+ *
+ *
+ * Distinct list of contained status:
+ *
+ *
+ *
PASS
+ *
SKIP
+ *
FAIL
+ *
+ */
+ private Set statusSet = new HashSet();
+
+ /**
+ * Path of dirs to resolve relative image path so there is a direct access
+ */
+ private String[] imagePathResolveDir;
+
+ protected ReportObservable() {
+ }
+
+ /**
+ * Subscribe the reporter to receive updates when making calls to the API
+ *
+ * @param reporter {@link ExtentReporter} reporter
+ */
+ protected void register(ExtentReporter reporter) {
+ reporterList.add(reporter);
+ reporter.start();
+ }
+
+ /**
+ * Unsubscribe the reporter. Calling unsubscribe will call the stop
+ * method and also remove the reporter from the list of started reporters
+ *
+ * @param reporter {@link ExtentReporter} reporter to unsubscribe
+ */
+ protected void deregister(ExtentReporter reporter) {
+
+ if (reporterList.contains((Object) reporter)) {
+ reporter.stop();
+ reporterList.remove(reporter);
+ }
+ }
+
+ /**
+ * Retrieve a list of all started reporters
+ *
+ * @return a list of {@link ExtentReporter} objects
+ */
+ protected List getReporterCollection() {
+ return reporterList;
+ }
+
+ /**
+ * Saves the started test and notifies all started reporters
+ *
+ * @param test a {@link Test} object
+ */
+ protected synchronized void saveTest(Test test) {
+ testList.add(test);
+ reporterList.forEach(x -> x.onTestStarted(test));
+ }
+
+ /**
+ * Removes the test and notifies all started reporters
+ *
+ * @param test a {@link Test} object
+ */
+ protected void removeTest(Test test) {
+ removeTestTestList(test);
+ removeTestTestAttributeContext(test);
+ reporterList.forEach(x -> x.onTestRemoved(test));
+ }
+
+ /**
+ * Removes a test from test list
+ *
+ * @param test a {@link Test} object
+ */
+ private void removeTestTestList(Test test) {
+ TestRemover.remove(testList, test);
+ refreshReportEntities();
+ }
+
+ /**
+ * Removes test from test list of each context
+ *
+ * @param test a {@link Test} object
+ */
+ private void removeTestTestAttributeContext(Test test) {
+ if (TestService.testHasCategory(test)) {
+ categoryContext.removeTest(test);
+ }
+ if (TestService.testHasAuthor(test)) {
+ authorContext.removeTest(test);
+ }
+ if (TestService.testHasDevice(test)) {
+ deviceContext.removeTest(test);
+ }
+ }
+
+ /**
+ * Refreshes report entities such as {@link ReportStatusStats} and list of
+ * distinct {@link Status}
+ */
+ private void refreshReportEntities() {
+ refreshReportStats();
+ refreshStatusList();
+ }
+
+ /**
+ * Refresh and notify all reports of {@link ReportStatusStats}
+ */
+ private void refreshReportStats() {
+ stats.refresh(testList);
+ }
+
+ /**
+ * Refresh and notify all reports of distinct status assigned to tests
+ */
+ private synchronized void refreshStatusList() {
+ statusSet.clear();
+ refreshStatusList(testList);
+ }
+
+ /**
+ * Refreshes distinct status list
+ *
+ * @param list a list of started {@link Test}
+ */
+ private synchronized void refreshStatusList(List list) {
+ if (list == null || list.isEmpty()) {
+ return;
+ }
+ list.forEach(x -> statusSet.add(x.getStatus()));
+ list.forEach(x -> refreshStatusList(x.getNodeContext().getAll()));
+ }
+
+ /**
+ * Notify reporters of the added node
+ *
+ * @param node a {@link Test} node
+ */
+ void addNode(Test node) {
+ reporterList.forEach(x -> x.onNodeStarted(node));
+ }
+
+ /**
+ * Notifies reporters with information of added {@link Log}
+ *
+ * @param test {@link Test} to which the event is added
+ * @param log {@link Log}
+ */
+ void addLog(Test test, Log log) {
+ reporterList.forEach(x -> x.onLogAdded(test, log));
+ }
+
+ /**
+ * Notifies reporters with information of added {@link Category}
+ *
+ * @param test {@link Test} to which the Category is added
+ * @param category {@link Category}
+ */
+ void assignCategory(Test test, Category category) {
+ reporterList.forEach(x -> x.onCategoryAssigned(test, category));
+ }
+
+ /**
+ * Notifies reporters with information of added {@link Author}
+ *
+ * @param test {@link Test} to which the Author is added
+ * @param author {@link Author}
+ */
+ void assignAuthor(Test test, Author author) {
+ reporterList.forEach(x -> x.onAuthorAssigned(test, author));
+ }
+
+ /**
+ * Notifies reporters with information of added {@link Author}
+ *
+ * @param test {@link Test} to which the Device is added
+ * @param device {@link Device}
+ */
+ void assignDevice(Test test, Device device) {
+ reporterList.forEach(x -> x.onDeviceAssigned(test, device));
+ }
+
+ /**
+ * Notifies reporters with information of added {@link ScreenCapture}
+ *
+ * @param test {@link Test} to which the ScreenCapture is added
+ * @param screenCapture {@link ScreenCapture}
+ *
+ * @throws IOException thrown if the {@link ScreenCapture} is not found
+ */
+ void addScreenCapture(Test test, ScreenCapture screenCapture) throws IOException {
+ ScreenCaptureService.resolvePath(screenCapture, imagePathResolveDir);
+ for (ExtentReporter r : reporterList) {
+ r.onScreenCaptureAdded(test, screenCapture);
+ }
+ }
+
+ /**
+ * Notifies reporters with information of added {@link ScreenCapture}
+ *
+ * @param test {@link Log} to which the ScreenCapture is added
+ * @param screenCapture {@link ScreenCapture}
+ *
+ * @throws IOException thrown if the {@link ScreenCapture} is not found
+ */
+ void addScreenCapture(Log log, ScreenCapture screenCapture) throws IOException {
+ ScreenCaptureService.resolvePath(screenCapture, imagePathResolveDir);
+ for (ExtentReporter r : reporterList) {
+ r.onScreenCaptureAdded(log, screenCapture);
+ }
+ }
+
+ /**
+ * Returns the context of author with the list of tests for each
+ *
+ * @return a {@link TestAttributeTestContextStore} object
+ */
+ protected TestAttributeTestContextStore getAuthorContextInfo() {
+ return authorContext;
+ }
+
+ /**
+ * Updates the status of the report or build
+ *
+ * @param status a {@link Status}
+ */
+ private void updateReportStatus(Status status) {
+ int statusIndex = Status.getStatusHierarchy().indexOf(status);
+ int reportStatusIndex = Status.getStatusHierarchy().indexOf(reportStatus);
+
+ reportStatus = statusIndex < reportStatusIndex ? status : reportStatus;
+ }
+
+ /**
+ * Ends the test
+ *
+ * @param test a {@link Test} object
+ */
+ private void endTest(Test test) {
+ test.end();
+ updateReportStatus(test.getStatus());
+ }
+
+ /**
+ * Collects and updates all run information and notifies all reporters.
+ * Depending upon the type of reporter, additional events can occur such as:
+ *
+ *
+ *
A file written to disk (eg. case of {@link BasicFileReporter}
+ *
A database being updated (eg. case of KlovReporter)
+ *
+ */
+ protected synchronized void flush() {
+ generateRecentStatus();
+ notifyReporters();
+ }
+
+ /**
+ * Collects run information from all tests for assigned {@link Category},
+ * {@link Author}, Exception, Nodes. This also ends and updates all internal
+ * test information and refreshes {@link ReportStatusStats} and the distinct
+ * list of {@link Status}
+ */
+ public synchronized void generateRecentStatus() {
+ if (testList == null || testList.isEmpty())
+ return;
+
+ reportEndDate = Calendar.getInstance().getTime();
+
+ for (Test test : testList) {
+ endTest(test);
+ test.setUsesManualConfiguration(getAllowManualConfig());
+ if (TestService.testHasCategory(test)) {
+ test.getCategoryContext().getAll().forEach(x -> categoryContext.setAttributeContext((Category) x, test));
+ }
+ if (TestService.testHasAuthor(test)) {
+ test.getAuthorContext().getAll().forEach(x -> authorContext.setAttributeContext((Author) x, test));
+ }
+ if (TestService.testHasDevice(test)) {
+ test.getDeviceContext().getAll().forEach(x -> deviceContext.setAttributeContext((Device) x, test));
+ }
+ if (TestService.testHasException(test)) {
+ test.getExceptionInfoContext().getAll().forEach(x -> exceptionContext.setExceptionContext(x, test));
+ }
+ if (TestService.testHasChildren(test)) {
+ Iterator iter = test.getNodeContext().getIterator();
+ while (iter.hasNext()) {
+ Test node = iter.next();
+ copyNodeAttributeAndRunTimeInfoToAttributeContexts(node);
+ node.setUsesManualConfiguration(getAllowManualConfig());
+ }
+ }
+ }
+
+ refreshReportEntities();
+ updateReportStartTimeForManualConfigurationSetting();
+ }
+
+ /**
+ * In case where manual configuration is used, calculate the correct timestamps
+ * based upon the timestamps assigned to tests
+ */
+ private void updateReportStartTimeForManualConfigurationSetting() {
+ if (getAllowManualConfig() && !testList.isEmpty()) {
+ Date minDate = testList.stream().map(t -> t.getStartTime()).min(Date::compareTo).get();
+ Date maxDate = testList.stream().map(t -> t.getEndTime()).max(Date::compareTo).get();
+ reportStartDate = reportStartDate.getTime() > minDate.getTime() ? minDate : reportStartDate;
+ reportEndDate = reportEndDate.getTime() < maxDate.getTime() ? maxDate : reportEndDate;
+ }
+ }
+
+ /**
+ * Traverse all nodes and refresh {@link Category}, {@link Author}, Exception
+ * and Node context information
+ *
+ * @param node a {@link Test} node
+ */
+ private void copyNodeAttributeAndRunTimeInfoToAttributeContexts(Test node) {
+ if (TestService.testHasCategory(node)) {
+ node.getCategoryContext().getAll().forEach(x -> categoryContext.setAttributeContext((Category) x, node));
+ }
+ if (TestService.testHasAuthor(node)) {
+ node.getAuthorContext().getAll().forEach(x -> authorContext.setAttributeContext((Author) x, node));
+ }
+ if (TestService.testHasDevice(node)) {
+ node.getDeviceContext().getAll().forEach(x -> deviceContext.setAttributeContext((Device) x, node));
+ }
+ if (TestService.testHasException(node)) {
+ node.getExceptionInfoContext().getAll().forEach(x -> exceptionContext.setExceptionContext(x, node));
+ }
+ if (TestService.testHasChildren(node)) {
+ node.getNodeContext().getAll().forEach(this::copyNodeAttributeAndRunTimeInfoToAttributeContexts);
+ }
+ }
+
+ /**
+ * Notify all reporters with complete run information
+ */
+ private synchronized void notifyReporters() {
+ if (!testList.isEmpty() && TestService.isTestBehaviorDriven(testList.get(0))) {
+ strategy = AnalysisStrategy.BDD;
+ }
+ ReportAggregates reportAggregates = new ReportAggregatesBuilder()
+ .setAuthorContext(authorContext)
+ .setCategoryContext(categoryContext)
+ .setDeviceContext(deviceContext)
+ .setExceptionContext(exceptionContext)
+ .setReportStatusStats(stats)
+ .setStatusCollection(statusSet)
+ .setSystemAttributeContext(systemAttributeContext)
+ .setTestList(testList)
+ .setTestRunnerLogs(testRunnerLogs)
+ .setStartTime(reportStartDate)
+ .setEndTime(reportEndDate)
+ .build();
+ reporterList.forEach(x -> x.setAnalysisStrategy(strategy));
+ reporterList.forEach(x -> x.flush(reportAggregates));
+ }
+
+ /**
+ * Ends logging, stops and clears the list of reporters
+ */
+ protected void end() {
+ flush();
+ reporterList.forEach(ExtentReporter::stop);
+ reporterList.clear();
+ }
+
+ /**
+ * Add a system attribute
+ *
+ * @param sa a {@link SystemAttribute} object
+ */
+ protected void setSystemInfo(SystemAttribute sa) {
+ systemAttributeContext.setSystemAttribute(sa);
+ }
+
+ /**
+ * Add a test runner log
+ *
+ * @param log a log event
+ */
+ protected void setTestRunnerLogs(String log) {
+ testRunnerLogs.add(log);
+ }
+
+ /**
+ * Updates the {@link AnalysisStrategy}
+ *
+ * @param strategy a {@link AnalysisStrategy} object
+ */
+ protected void setAnalysisStrategy(AnalysisStrategy strategy) {
+ this.strategy = strategy;
+ stats = new ReportStatusStats(strategy);
+ }
+
+ protected void setMediaPathResolveDir(String[] imagePathResolveDir) {
+ this.imagePathResolveDir = imagePathResolveDir;
+ }
+
+ /**
+ * Setting to allow user driven configuration for test time-stamps
+ *
+ * @param useManualConfig setting for manual configuration
+ */
+ protected void setAllowManualConfig(boolean useManualConfig) {
+ this.usesManualConfiguration = useManualConfig;
+ }
+
+ /**
+ * Returns the current value of using manual configuration for test time-stamps
+ *
+ * @return setting for manual configuration
+ */
+ protected boolean getAllowManualConfig() {
+ return usesManualConfiguration;
+ }
+
+ /**
+ * Return the {@link ReportStatusStats} object
+ *
+ * @return a {@link ReportStatusStats} object
+ */
+ protected ReportStatusStats getStats() {
+ generateRecentStatus();
+ return stats;
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/aventstack/extentreports/ReportService.java b/src/main/java/com/aventstack/extentreports/ReportService.java
index 4fdfde2..2932d67 100644
--- a/src/main/java/com/aventstack/extentreports/ReportService.java
+++ b/src/main/java/com/aventstack/extentreports/ReportService.java
@@ -1,13 +1,16 @@
package com.aventstack.extentreports;
import com.aventstack.extentreports.reporter.AbstractReporter;
+import com.aventstack.extentreports.reporter.ExtentReporter;
/**
- * The main service for {@link ExtentReports} which allows attaching a reporter of type
- * {@link AbstractReporter}
+ * The main service for {@link ExtentReports} which allows attaching a reporter
+ * of type {@link AbstractReporter}
*/
public interface ReportService {
-
- void attachReporter(ExtentReporter... reporter);
-
-}
+
+ void attachReporter(ExtentReporter... reporter);
+
+ void generateRecentStatus();
+
+}
\ No newline at end of file
diff --git a/src/main/java/com/aventstack/extentreports/ReportStatusStats.java b/src/main/java/com/aventstack/extentreports/ReportStatusStats.java
index 5236617..8c5a7fc 100644
--- a/src/main/java/com/aventstack/extentreports/ReportStatusStats.java
+++ b/src/main/java/com/aventstack/extentreports/ReportStatusStats.java
@@ -1,387 +1,602 @@
package com.aventstack.extentreports;
+import java.util.Iterator;
import java.util.List;
-import com.aventstack.extentreports.exceptions.InvalidAnalysisStrategyException;
import com.aventstack.extentreports.gherkin.model.Scenario;
+import com.aventstack.extentreports.model.Log;
import com.aventstack.extentreports.model.Test;
/**
*
- * This class maintains the total count of tests and its nodes along with
- * their statuses for a given run session
+ * This class maintains the total count of tests and its nodes along with their
+ * statuses for a given run session
*/
public class ReportStatusStats {
-
- private List testList;
- private AnalysisStrategy strategy = AnalysisStrategy.TEST;
-
- private int parentPass = 0;
- private int parentFail = 0;
- private int parentFatal = 0;
- private int parentError = 0;
- private int parentWarning = 0;
- private int parentSkip = 0;
- private int parentExceptions = 0;
-
- private int childPass = 0;
- private int childFail = 0;
- private int childFatal = 0;
- private int childError = 0;
- private int childWarning = 0;
- private int childSkip = 0;
- private int childInfo = 0;
- private int childDebug = 0;
- private int childExceptions = 0;
-
- private int grandChildPass = 0;
- private int grandChildFail = 0;
- private int grandChildFatal = 0;
- private int grandChildError = 0;
- private int grandChildWarning = 0;
- private int grandChildSkip = 0;
- private int grandChildInfo = 0;
- private int grandChildDebug = 0;
- private int grandChildExceptions = 0;
-
- public ReportStatusStats(AnalysisStrategy strategy) {
- this.strategy = strategy;
- }
-
- public void refresh(List testList) {
- reset();
- this.testList = testList;
- refreshStats();
- }
-
- private void reset() {
- parentPass = 0;
- parentFail = 0;
- parentFatal = 0;
- parentError = 0;
- parentWarning = 0;
- parentSkip = 0;
- parentExceptions = 0;
-
- childPass = 0;
- childFail = 0;
- childFatal = 0;
- childError = 0;
- childWarning = 0;
- childSkip = 0;
- childInfo = 0;
- childExceptions = 0;
-
- grandChildPass = 0;
- grandChildFail = 0;
- grandChildFatal = 0;
- grandChildError = 0;
- grandChildWarning = 0;
- grandChildSkip = 0;
- grandChildInfo = 0;
- grandChildExceptions = 0;
- }
-
- public int getParentCount() {
- return getParentCountPass() +
- getParentCountFail() +
- getParentCountFatal() +
- getParentCountError() +
- getParentCountWarning() +
- getParentCountSkip();
- }
- public int getParentCountPass() { return parentPass; }
- public int getParentCountFail() { return parentFail; }
- public int getParentCountFatal() { return parentFatal; }
- public int getParentCountError() { return parentError; }
- public int getParentCountWarning() { return parentWarning; }
- public int getParentCountSkip() { return parentSkip; }
- public int getParentCountExceptions() { return parentExceptions; }
-
- public float getParentPercentagePass() {
- float p = getParentCount() > 0 ? (float)getParentCountPass()/(float)getParentCount() : 0;
- return p*100;
- }
- public float getParentPercentageFail() {
- float p = getParentCount() > 0 ? ((float)getParentCountFail()+(float)getParentCountFatal())/(float)getParentCount() : 0;
- return p*100;
- }
- public float getParentPercentageOthers() {
- float p = getParentCount() > 0 ? ((float)getParentCountWarning()+(float)getParentCountError())/(float)getParentCount() : 0;
- return p*100;
- }
- public float getParentPercentageSkip() {
- float p = getParentCount() > 0 ? (float)getParentCountSkip()/(float)getParentCount() : 0;
- return p*100;
- }
-
- public int getChildCount() {
- return getChildCountPass() +
- getChildCountFail() +
- getChildCountFatal() +
- getChildCountError() +
- getChildCountWarning() +
- getChildCountSkip() +
- getChildCountInfo();
- }
- public int getChildCountPass() { return childPass; }
- public int getChildCountFail() { return childFail; }
- public int getChildCountFatal() { return childFatal; }
- public int getChildCountError() { return childError; }
- public int getChildCountWarning() { return childWarning; }
- public int getChildCountSkip() { return childSkip; }
- public int getChildCountInfo() { return childInfo; }
- public int getChildCountDebug() { return childDebug; }
- public int getChildCountExceptions() { return childExceptions; }
-
- public float getChildPercentagePass() {
- float p = getChildCount() > 0 ? (float)getChildCountPass()/(float)getChildCount() : 0;
- return p*100;
- }
- public float getChildPercentageFail() {
- float p = getChildCount() > 0 ? ((float)getChildCountFail()+(float)getChildCountFatal())/(float)getChildCount() : 0;
- return p*100;
- }
- public float getChildPercentageOthers() {
- float p = getChildCount() > 0 ? (((float)getChildCountWarning()+(float)getChildCountError()+(float)getChildCountSkip()+(float)getChildCountInfo())/(float)getChildCount()) : 0;
- return p*100;
- }
- public float getChildPercentageSkip() {
- float p = getChildCount() > 0 ? (float)getChildCountSkip()/(float)getChildCount() : 0;
- return p*100;
- }
-
- public int getGrandChildCount() {
- return getGrandChildCountPass() +
- getGrandChildCountFail() +
- getGrandChildCountFatal() +
- getGrandChildCountError() +
- getGrandChildCountWarning() +
- getGrandChildCountSkip() +
- getGrandChildCountInfo();
- }
- public int getGrandChildCountPass() { return grandChildPass; }
- public int getGrandChildCountFail() { return grandChildFail; }
- public int getGrandChildCountFatal() { return grandChildFatal; }
- public int getGrandChildCountError() { return grandChildError; }
- public int getGrandChildCountWarning() { return grandChildWarning; }
- public int getGrandChildCountSkip() { return grandChildSkip; }
- public int getGrandChildCountInfo() { return grandChildInfo; }
- public int getGrandChildCountDebug() { return grandChildDebug; }
- public int getGrandChildCountExceptions() { return grandChildExceptions; }
-
- public float getGrandChildPercentagePass() {
- float p = getGrandChildCount() > 0 ? (float)getGrandChildCountPass()/(float)getGrandChildCount() : 0;
- return p*100;
- }
- public float getGrandChildPercentageFail() {
- float p = getGrandChildCount() > 0 ? ((float)getGrandChildCountFail()+(float)getGrandChildCountFatal())/(float)getGrandChildCount() : 0;
- return p*100;
- }
- public float getGrandChildPercentageOthers() {
- float p = getGrandChildCount() > 0 ? (((float)getGrandChildCountWarning()+(float)getGrandChildCountError()+(float)getGrandChildCountSkip()+(float)getGrandChildCountInfo())/(float)getGrandChildCount()) : 0;
- return p*100;
- }
- public float getGrandChildPercentageSkip() {
- float p = getGrandChildCount() > 0 ? (float)getGrandChildCountSkip()/(float)getGrandChildCount() : 0;
- return p*100;
- }
-
- private void refreshStats() {
- testList.forEach(this::addTestForStatusStatsUpdate);
- }
-
- private void addTestForStatusStatsUpdate(Test test) {
- if (test.isBehaviorDrivenType() || (test.hasChildren() && test.getNodeContext().get(0).isBehaviorDrivenType())) {
- updateGroupCountsBDD(test);
- return;
- }
-
- if (strategy == AnalysisStrategy.TEST || strategy == AnalysisStrategy.CLASS) {
- updateGroupCountsTestStrategy(test);
- return;
- }
-
- if (strategy == AnalysisStrategy.SUITE) {
- updateGroupCountsSuiteStrategy(test);
- return;
- }
-
- throw new InvalidAnalysisStrategyException("No such strategy found: " + strategy);
- }
-
- private void updateGroupCountsSuiteStrategy(Test test) {
- incrementItemCountByStatus(ItemLevel.PARENT, test.getStatus());
-
- if (test.hasChildren()) {
- test.getNodeContext().getAll().forEach(x -> {
- incrementItemCountByStatus(ItemLevel.CHILD, x.getStatus());
-
- if (x.hasChildren())
- x.getNodeContext().getAll().forEach(n -> incrementItemCountByStatus(ItemLevel.GRANDCHILD, n.getStatus()));
- });
- }
- }
-
- private void updateGroupCountsBDD(Test test) {
- incrementItemCountByStatus(ItemLevel.PARENT, test.getStatus());
-
- if (test.hasChildren()) {
- test.getNodeContext().getAll().forEach(x -> {
- if (x.getBehaviorDrivenType() == Scenario.class)
- incrementItemCountByStatus(ItemLevel.CHILD, x.getStatus());
-
- if (x.hasChildren()) {
- x.getNodeContext().getAll().forEach(n -> {
- if (n.getBehaviorDrivenType() == Scenario.class) {
- incrementItemCountByStatus(ItemLevel.CHILD, n.getStatus());
-
- n.getNodeContext().getAll().forEach(z -> incrementItemCountByStatus(ItemLevel.GRANDCHILD, z.getStatus()));
- }
- else {
- incrementItemCountByStatus(ItemLevel.GRANDCHILD, n.getStatus());
- }
- });
- }
- });
- }
- }
-
- private void updateGroupCountsTestStrategy(Test test) {
- incrementItemCountByStatus(ItemLevel.PARENT, test.getStatus());
-
- if (test.hasChildren()) {
- updateGroupCountsTestStrategyChildren(test);
- }
- }
-
- private void updateGroupCountsTestStrategyChildren(Test test) {
- test.getNodeContext().getAll().forEach(x -> {
- if (!x.hasChildren()) {
- incrementItemCountByStatus(ItemLevel.CHILD, x.getStatus());
- } else {
- updateGroupCountsTestStrategyChildren(x);
- }
- });
- }
-
- enum ItemLevel {
- PARENT,
- CHILD,
- GRANDCHILD
- }
-
- private void incrementItemCountByStatus(ItemLevel item, Status status) {
- switch (item) {
- case PARENT:
- incrementParent(status);
- break;
-
- case CHILD:
- incrementChild(status);
- break;
-
- case GRANDCHILD:
- incrementGrandChild(status);
- break;
-
- default:
- break;
- }
- }
-
- private void incrementParent(Status status) {
- switch (status) {
- case PASS:
- parentPass++;
- return;
- case FAIL:
- parentFail++;
- break;
- case FATAL:
- parentFatal++;
- break;
- case ERROR:
- parentError++;
- break;
- case WARNING:
- parentWarning++;
- break;
- case SKIP:
- parentSkip++;
- break;
- default:
- break;
- }
-
- parentExceptions++;
- }
-
- private void incrementChild(Status status) {
- switch (status) {
- case PASS:
- childPass++;
- break;
- case FAIL:
- childFail++;
- break;
- case FATAL:
- childFatal++;
- break;
- case ERROR:
- childError++;
- break;
- case WARNING:
- childWarning++;
- break;
- case SKIP:
- childSkip++;
- break;
- case INFO:
- childInfo++;
- break;
- case DEBUG:
- childDebug++;
- break;
- default:
- break;
- }
-
- if (status != Status.PASS && status != Status.INFO)
- childExceptions++;
- }
-
- private void incrementGrandChild(Status status) {
- switch (status) {
- case PASS:
- grandChildPass++;
- break;
- case FAIL:
- grandChildFail++;
- break;
- case FATAL:
- grandChildFatal++;
- break;
- case ERROR:
- grandChildError++;
- break;
- case WARNING:
- grandChildWarning++;
- break;
- case SKIP:
- grandChildSkip++;
- break;
- case INFO:
- grandChildInfo++;
- break;
- case DEBUG:
- grandChildDebug++;
- break;
- default:
- break;
- }
-
- if (status != Status.PASS && status != Status.INFO)
- grandChildExceptions++;
- }
-}
+
+ private List testList;
+ private AnalysisStrategy strategy = AnalysisStrategy.TEST;
+
+ private int parentPass = 0;
+ private int parentFail = 0;
+ private int parentFatal = 0;
+ private int parentError = 0;
+ private int parentWarning = 0;
+ private int parentSkip = 0;
+ private int parentExceptions = 0;
+
+ private int childPass = 0;
+ private int childFail = 0;
+ private int childFatal = 0;
+ private int childError = 0;
+ private int childWarning = 0;
+ private int childSkip = 0;
+ private int childInfo = 0;
+ private int childDebug = 0;
+ private int childExceptions = 0;
+
+ private int grandChildPass = 0;
+ private int grandChildFail = 0;
+ private int grandChildFatal = 0;
+ private int grandChildError = 0;
+ private int grandChildWarning = 0;
+ private int grandChildSkip = 0;
+ private int grandChildInfo = 0;
+ private int grandChildDebug = 0;
+ private int grandChildExceptions = 0;
+
+ private int eventsPass = 0;
+ private int eventsFail = 0;
+ private int eventsFatal = 0;
+ private int eventsError = 0;
+ private int eventsWarning = 0;
+ private int eventsSkip = 0;
+ private int eventsInfo = 0;
+ private int eventsDebug = 0;
+ private int eventsExceptions = 0;
+
+ public ReportStatusStats(AnalysisStrategy strategy) {
+ this.strategy = strategy;
+ }
+
+ public void refresh(List testList) {
+ reset();
+ this.testList = testList;
+ refreshStats();
+ }
+
+ private void reset() {
+ parentPass = 0;
+ parentFail = 0;
+ parentFatal = 0;
+ parentError = 0;
+ parentWarning = 0;
+ parentSkip = 0;
+ parentExceptions = 0;
+
+ childPass = 0;
+ childFail = 0;
+ childFatal = 0;
+ childError = 0;
+ childWarning = 0;
+ childSkip = 0;
+ childInfo = 0;
+ childExceptions = 0;
+
+ grandChildPass = 0;
+ grandChildFail = 0;
+ grandChildFatal = 0;
+ grandChildError = 0;
+ grandChildWarning = 0;
+ grandChildSkip = 0;
+ grandChildInfo = 0;
+ grandChildExceptions = 0;
+
+ eventsPass = 0;
+ eventsFail = 0;
+ eventsFatal = 0;
+ eventsError = 0;
+ eventsWarning = 0;
+ eventsSkip = 0;
+ eventsInfo = 0;
+ eventsDebug = 0;
+ eventsExceptions = 0;
+ }
+
+ public int getParentCount() {
+ return getParentCountPass() + getParentCountFail() + getParentCountFatal() + getParentCountError()
+ + getParentCountWarning() + getParentCountSkip();
+ }
+
+ public int getParentCountPass() {
+ return parentPass;
+ }
+
+ public int getParentCountFail() {
+ return parentFail;
+ }
+
+ public int getParentCountFatal() {
+ return parentFatal;
+ }
+
+ public int getParentCountError() {
+ return parentError;
+ }
+
+ public int getParentCountWarning() {
+ return parentWarning;
+ }
+
+ public int getParentCountSkip() {
+ return parentSkip;
+ }
+
+ public int getParentCountExceptions() {
+ return parentExceptions;
+ }
+
+ public float getParentPercentagePass() {
+ float p = getParentCount() > 0 ? (float) getParentCountPass() / (float) getParentCount() : 0;
+ return p * 100;
+ }
+
+ public float getParentPercentageFail() {
+ float p = getParentCount() > 0
+ ? ((float) getParentCountFail() + (float) getParentCountFatal()) / (float) getParentCount()
+ : 0;
+ return p * 100;
+ }
+
+ public float getParentPercentageOthers() {
+ float p = getParentCount() > 0
+ ? ((float) getParentCountWarning() + (float) getParentCountError()) / (float) getParentCount()
+ : 0;
+ return p * 100;
+ }
+
+ public float getParentPercentageSkip() {
+ float p = getParentCount() > 0 ? (float) getParentCountSkip() / (float) getParentCount() : 0;
+ return p * 100;
+ }
+
+ public int getChildCount() {
+ return getChildCountPass() + getChildCountFail() + getChildCountFatal() + getChildCountError()
+ + getChildCountWarning() + getChildCountSkip() + getChildCountInfo();
+ }
+
+ public int getChildCountPass() {
+ return childPass;
+ }
+
+ public int getChildCountFail() {
+ return childFail;
+ }
+
+ public int getChildCountFatal() {
+ return childFatal;
+ }
+
+ public int getChildCountError() {
+ return childError;
+ }
+
+ public int getChildCountWarning() {
+ return childWarning;
+ }
+
+ public int getChildCountSkip() {
+ return childSkip;
+ }
+
+ public int getChildCountInfo() {
+ return childInfo;
+ }
+
+ public int getChildCountDebug() {
+ return childDebug;
+ }
+
+ public int getChildCountExceptions() {
+ return childExceptions;
+ }
+
+ public float getChildPercentagePass() {
+ float p = getChildCount() > 0 ? (float) getChildCountPass() / (float) getChildCount() : 0;
+ return p * 100;
+ }
+
+ public float getChildPercentageFail() {
+ float p = getChildCount() > 0
+ ? ((float) getChildCountFail() + (float) getChildCountFatal()) / (float) getChildCount()
+ : 0;
+ return p * 100;
+ }
+
+ public float getChildPercentageOthers() {
+ float p = getChildCount() > 0
+ ? (((float) getChildCountWarning() + (float) getChildCountError() + (float) getChildCountSkip()
+ + (float) getChildCountInfo()) / (float) getChildCount())
+ : 0;
+ return p * 100;
+ }
+
+ public float getChildPercentageSkip() {
+ float p = getChildCount() > 0 ? (float) getChildCountSkip() / (float) getChildCount() : 0;
+ return p * 100;
+ }
+
+ public int getGrandChildCount() {
+ return getGrandChildCountPass() + getGrandChildCountFail() + getGrandChildCountFatal()
+ + getGrandChildCountError() + getGrandChildCountWarning() + getGrandChildCountSkip()
+ + getGrandChildCountInfo();
+ }
+
+ public int getGrandChildCountPass() {
+ return grandChildPass;
+ }
+
+ public int getGrandChildCountFail() {
+ return grandChildFail;
+ }
+
+ public int getGrandChildCountFatal() {
+ return grandChildFatal;
+ }
+
+ public int getGrandChildCountError() {
+ return grandChildError;
+ }
+
+ public int getGrandChildCountWarning() {
+ return grandChildWarning;
+ }
+
+ public int getGrandChildCountSkip() {
+ return grandChildSkip;
+ }
+
+ public int getGrandChildCountInfo() {
+ return grandChildInfo;
+ }
+
+ public int getGrandChildCountDebug() {
+ return grandChildDebug;
+ }
+
+ public int getGrandChildCountExceptions() {
+ return grandChildExceptions;
+ }
+
+ public float getGrandChildPercentagePass() {
+ float p = getGrandChildCount() > 0 ? (float) getGrandChildCountPass() / (float) getGrandChildCount() : 0;
+ return p * 100;
+ }
+
+ public float getGrandChildPercentageFail() {
+ float p = getGrandChildCount() > 0
+ ? ((float) getGrandChildCountFail() + (float) getGrandChildCountFatal()) / (float) getGrandChildCount()
+ : 0;
+ return p * 100;
+ }
+
+ public float getGrandChildPercentageOthers() {
+ float p = getGrandChildCount() > 0
+ ? (((float) getGrandChildCountWarning() + (float) getGrandChildCountError()
+ + (float) getGrandChildCountSkip() + (float) getGrandChildCountInfo())
+ / (float) getGrandChildCount())
+ : 0;
+ return p * 100;
+ }
+
+ public float getGrandChildPercentageSkip() {
+ float p = getGrandChildCount() > 0 ? (float) getGrandChildCountSkip() / (float) getGrandChildCount() : 0;
+ return p * 100;
+ }
+
+ public int getEventsCount() {
+ return getEventsCountPass() + getEventsCountFail() + getEventsCountFatal()
+ + getEventsCountError() + getEventsCountWarning() + getEventsCountSkip()
+ + getEventsCountInfo();
+ }
+
+ public int getEventsCountPass() {
+ return eventsPass;
+ }
+
+ public int getEventsCountFail() {
+ return eventsFail;
+ }
+
+ public int getEventsCountFatal() {
+ return eventsFatal;
+ }
+
+ public int getEventsCountError() {
+ return eventsError;
+ }
+
+ public int getEventsCountWarning() {
+ return eventsWarning;
+ }
+
+ public int getEventsCountSkip() {
+ return eventsSkip;
+ }
+
+ public int getEventsCountInfo() {
+ return eventsInfo;
+ }
+
+ public int getEventsCountDebug() {
+ return eventsDebug;
+ }
+
+ public int getEventsCountExceptions() {
+ return eventsExceptions;
+ }
+
+ public float getEventsPercentagePass() {
+ float p = getEventsCount() > 0 ? (float) getEventsCountPass() / (float) getEventsCount() : 0;
+ return p * 100;
+ }
+
+ public float getEventsPercentageFail() {
+ float p = getEventsCount() > 0
+ ? ((float) getEventsCountFail() + (float) getEventsCountFatal()) / (float) getEventsCount()
+ : 0;
+ return p * 100;
+ }
+
+ public float getEventsPercentageOthers() {
+ float p = getEventsCount() > 0
+ ? (((float) getEventsCountWarning() + (float) getEventsCountError()
+ + (float) getEventsCountSkip() + (float) getEventsCountInfo())
+ / (float) getEventsCount())
+ : 0;
+ return p * 100;
+ }
+
+ public float getEventsPercentageSkip() {
+ float p = getEventsCount() > 0 ? (float) getEventsCountSkip() / (float) getEventsCount() : 0;
+ return p * 100;
+ }
+
+ private void refreshStats() {
+ testList.forEach(this::addTestForStatusStatsUpdate);
+ }
+
+ private void addTestForStatusStatsUpdate(Test test) {
+ updateEventsCount(test);
+
+ if (test.getBddType() != null
+ || (!test.getNodeContext().isEmpty() && test.getNodeContext().get(0).getBddType() != null)) {
+ updateGroupCountsBDD(test);
+ return;
+ }
+
+ if (strategy == AnalysisStrategy.TEST || strategy == AnalysisStrategy.CLASS) {
+ updateGroupCountsTestStrategy(test);
+ return;
+ }
+
+ if (strategy == AnalysisStrategy.SUITE) {
+ updateGroupCountsSuiteStrategy(test);
+ return;
+ }
+
+ throw new InvalidAnalysisStrategyException("No such strategy found: " + strategy);
+ }
+
+ private void updateEventsCount(Test test) {
+ test.getLogContext().getAll().stream()
+ .map(Log::getStatus)
+ .forEach(this::incrementEvent);
+ Iterator iter = test.getNodeContext().getIterator();
+ while (iter.hasNext()) {
+ Test node = iter.next();
+ updateEventsCount(node);
+ }
+ }
+
+ private void updateGroupCountsSuiteStrategy(Test test) {
+ incrementItemCountByStatus(ItemLevel.PARENT, test.getStatus());
+
+ if (!test.getNodeContext().isEmpty()) {
+ for (Test x : test.getNodeContext().getAll()) {
+ incrementItemCountByStatus(ItemLevel.CHILD, x.getStatus());
+ if (!x.getNodeContext().isEmpty()) {
+ x.getNodeContext().getAll()
+ .forEach(n -> incrementItemCountByStatus(ItemLevel.GRANDCHILD, n.getStatus()));
+ }
+ }
+ }
+ }
+
+ private void updateGroupCountsBDD(Test test) {
+ incrementItemCountByStatus(ItemLevel.PARENT, test.getStatus());
+
+ if (!test.getNodeContext().isEmpty()) {
+ for (Test x : test.getNodeContext().getAll()) {
+ if (x.getBddType() == Scenario.class) {
+ incrementItemCountByStatus(ItemLevel.CHILD, x.getStatus());
+ }
+ if (!x.getNodeContext().isEmpty()) {
+ for (Test n : x.getNodeContext().getAll()) {
+ if (n.getBddType() == Scenario.class) {
+ incrementItemCountByStatus(ItemLevel.CHILD, n.getStatus());
+ n.getNodeContext().getAll()
+ .forEach(z -> incrementItemCountByStatus(ItemLevel.GRANDCHILD, z.getStatus()));
+ } else {
+ incrementItemCountByStatus(ItemLevel.GRANDCHILD, n.getStatus());
+ }
+ }
+ }
+ }
+ }
+ }
+
+ private void updateGroupCountsTestStrategy(Test test) {
+ incrementItemCountByStatus(ItemLevel.PARENT, test.getStatus());
+
+ if (!test.getNodeContext().isEmpty()) {
+ updateGroupCountsTestStrategyChildren(test);
+ }
+ }
+
+ private void updateGroupCountsTestStrategyChildren(Test test) {
+ test.getNodeContext().getAll().forEach(x -> {
+ if (x.getNodeContext().isEmpty()) {
+ incrementItemCountByStatus(ItemLevel.CHILD, x.getStatus());
+ } else {
+ updateGroupCountsTestStrategyChildren(x);
+ }
+ });
+ }
+
+ enum ItemLevel {
+ PARENT, CHILD, GRANDCHILD
+ }
+
+ private void incrementItemCountByStatus(ItemLevel item, Status status) {
+ switch (item) {
+ case PARENT:
+ incrementParent(status);
+ break;
+ case CHILD:
+ incrementChild(status);
+ break;
+ case GRANDCHILD:
+ incrementGrandChild(status);
+ break;
+ default:
+ break;
+ }
+ }
+
+ private void incrementParent(Status status) {
+ switch (status) {
+ case PASS:
+ parentPass++;
+ return;
+ case FAIL:
+ parentFail++;
+ break;
+ case FATAL:
+ parentFatal++;
+ break;
+ case ERROR:
+ parentError++;
+ break;
+ case WARNING:
+ parentWarning++;
+ break;
+ case SKIP:
+ parentSkip++;
+ break;
+ default:
+ break;
+ }
+
+ parentExceptions++;
+ }
+
+ private void incrementChild(Status status) {
+ switch (status) {
+ case PASS:
+ childPass++;
+ break;
+ case FAIL:
+ childFail++;
+ break;
+ case FATAL:
+ childFatal++;
+ break;
+ case ERROR:
+ childError++;
+ break;
+ case WARNING:
+ childWarning++;
+ break;
+ case SKIP:
+ childSkip++;
+ break;
+ case INFO:
+ childInfo++;
+ break;
+ case DEBUG:
+ childDebug++;
+ break;
+ default:
+ break;
+ }
+
+ if (status != Status.PASS && status != Status.INFO)
+ childExceptions++;
+ }
+
+ private void incrementGrandChild(Status status) {
+ switch (status) {
+ case PASS:
+ grandChildPass++;
+ break;
+ case FAIL:
+ grandChildFail++;
+ break;
+ case FATAL:
+ grandChildFatal++;
+ break;
+ case ERROR:
+ grandChildError++;
+ break;
+ case WARNING:
+ grandChildWarning++;
+ break;
+ case SKIP:
+ grandChildSkip++;
+ break;
+ case INFO:
+ grandChildInfo++;
+ break;
+ case DEBUG:
+ grandChildDebug++;
+ break;
+ default:
+ break;
+ }
+
+ if (status != Status.PASS && status != Status.INFO)
+ grandChildExceptions++;
+ }
+
+ private void incrementEvent(Status status) {
+ switch (status) {
+ case PASS:
+ eventsPass++;
+ break;
+ case FAIL:
+ eventsFail++;
+ break;
+ case FATAL:
+ eventsFatal++;
+ break;
+ case ERROR:
+ eventsError++;
+ break;
+ case WARNING:
+ eventsWarning++;
+ break;
+ case SKIP:
+ eventsSkip++;
+ break;
+ case INFO:
+ eventsInfo++;
+ break;
+ case DEBUG:
+ eventsDebug++;
+ break;
+ default:
+ break;
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/aventstack/extentreports/RunResult.java b/src/main/java/com/aventstack/extentreports/RunResult.java
index b608cf9..426197f 100644
--- a/src/main/java/com/aventstack/extentreports/RunResult.java
+++ b/src/main/java/com/aventstack/extentreports/RunResult.java
@@ -1,5 +1,4 @@
package com.aventstack.extentreports;
-
/**
* Marker interface for the run result with a single getStatus() method
*
@@ -8,4 +7,4 @@ public interface RunResult {
Status getStatus();
-}
+}
\ No newline at end of file
diff --git a/src/main/java/com/aventstack/extentreports/Status.java b/src/main/java/com/aventstack/extentreports/Status.java
index 8ab30bd..f4ca613 100644
--- a/src/main/java/com/aventstack/extentreports/Status.java
+++ b/src/main/java/com/aventstack/extentreports/Status.java
@@ -1,7 +1,7 @@
package com.aventstack.extentreports;
-
import java.io.Serializable;
import java.util.Arrays;
+import java.util.Collection;
import java.util.List;
/**
@@ -48,12 +48,12 @@ public static List getStatusHierarchy() {
return statusHierarchy;
}
- public static Status getHighestStatus(List statusList) {
+ public static Status getHighestStatus(Collection statusCollection) {
Status highestStatus = Status.PASS;
- if (statusList == null || statusList.isEmpty()) {
+ if (statusCollection == null || statusCollection.isEmpty()) {
return highestStatus;
}
- for (Status status : statusList) {
+ for (Status status : statusCollection) {
highestStatus = Status.getStatusHierarchy().indexOf(status) < Status.getStatusHierarchy().indexOf(highestStatus)
? status
: highestStatus;
diff --git a/src/main/java/com/aventstack/extentreports/StatusConfigurator.java b/src/main/java/com/aventstack/extentreports/StatusConfigurator.java
index 70713b3..9e5cc6a 100644
--- a/src/main/java/com/aventstack/extentreports/StatusConfigurator.java
+++ b/src/main/java/com/aventstack/extentreports/StatusConfigurator.java
@@ -4,26 +4,29 @@
public class StatusConfigurator {
- private static class StatusConfiguratorInstance {
- static final StatusConfigurator INSTANCE = new StatusConfigurator();
-
- private StatusConfiguratorInstance() { }
- }
-
- private StatusConfigurator() { }
-
- public static StatusConfigurator getInstance() {
- return StatusConfiguratorInstance.INSTANCE;
- }
-
- public List getStatusHierarchy() {
- return Status.getStatusHierarchy();
- }
- public void setStatusHierarchy(List statusHierarchy) {
- Status.setStatusHierarchy(statusHierarchy);
- }
-
- public void resetStatusHierarchy() {
- Status.resetStatusHierarchy();
- }
+ private static class StatusConfiguratorInstance {
+ static final StatusConfigurator INSTANCE = new StatusConfigurator();
+
+ private StatusConfiguratorInstance() {
+ }
+ }
+
+ private StatusConfigurator() {
+ }
+
+ public static StatusConfigurator getInstance() {
+ return StatusConfiguratorInstance.INSTANCE;
+ }
+
+ public List getStatusHierarchy() {
+ return Status.getStatusHierarchy();
+ }
+
+ public void setStatusHierarchy(List statusHierarchy) {
+ Status.setStatusHierarchy(statusHierarchy);
+ }
+
+ public void resetStatusHierarchy() {
+ Status.resetStatusHierarchy();
+ }
}
\ No newline at end of file
diff --git a/src/main/java/com/aventstack/extentreports/SystemAttributeContext.java b/src/main/java/com/aventstack/extentreports/SystemAttributeContext.java
deleted file mode 100644
index 1bf48ea..0000000
--- a/src/main/java/com/aventstack/extentreports/SystemAttributeContext.java
+++ /dev/null
@@ -1,29 +0,0 @@
-package com.aventstack.extentreports;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import com.aventstack.extentreports.model.SystemAttribute;
-
-/**
- * A simple key-value pair collection to store System/Environment information
- *
- */
-public class SystemAttributeContext {
-
- private List sysAttrCollection;
-
- public SystemAttributeContext() {
- sysAttrCollection = new ArrayList<>();
- }
-
- public void setSystemAttribute(SystemAttribute sa) {
- sysAttrCollection.add(sa);
- }
-
- public List getSystemAttributeList() { return sysAttrCollection; }
-
- public void clear() {
- sysAttrCollection.clear();
- }
-}
diff --git a/src/main/java/com/aventstack/extentreports/TestAttributeTestContextProvider.java b/src/main/java/com/aventstack/extentreports/TestAttributeTestContextProvider.java
deleted file mode 100644
index d24b48a..0000000
--- a/src/main/java/com/aventstack/extentreports/TestAttributeTestContextProvider.java
+++ /dev/null
@@ -1,66 +0,0 @@
-package com.aventstack.extentreports;
-
-import java.util.ArrayList;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Optional;
-
-import com.aventstack.extentreports.model.Test;
-import com.aventstack.extentreports.model.TestAttribute;
-import com.aventstack.extentreports.model.TestAttributeTestContext;
-
-/**
- * Uses an attribute context for {@link TestAttribute} (Category, Device, Author etc.)
- * and tracks the collection of tests segregated by the type {@link TestAttribute}
- *
- * @param A {@link TestAttribute} type
- */
-public class TestAttributeTestContextProvider {
-
- private List> testAttrCollection;
-
- public TestAttributeTestContextProvider() {
- testAttrCollection = new ArrayList<>();
- }
-
- public void setAttributeContext(T attr, Test test) {
- Optional> testOptionalTestContext = testAttrCollection
- .stream()
- .filter(x -> x.getName().equals(attr.getName()))
- .findFirst();
-
- if (testOptionalTestContext.isPresent()) {
- List testList = testOptionalTestContext.get().getTestList();
-
- boolean b = testList
- .stream()
- .anyMatch(t -> t.getID() == test.getID());
-
- if (!b) {
- testOptionalTestContext.get().setTest(test);
- }
- testOptionalTestContext.get().refreshTestStatusCounts();
- }
- else {
- TestAttributeTestContext testAttrContext = new TestAttributeTestContext<>(attr);
- testAttrContext.setTest(test);
- testAttrCollection.add(testAttrContext);
- }
- }
-
- public void removeTest(Test test) {
- Iterator> iter = testAttrCollection.iterator();
- while (iter.hasNext()) {
- TestAttributeTestContext context = iter.next();
- TestRemover.remove(context.getTestList(), test);
- if (context.isEmpty()) {
- iter.remove();
- }
- }
- }
-
- public List> getTestAttributeTestContextList() {
- return testAttrCollection;
- }
-
-}
diff --git a/src/main/java/com/aventstack/extentreports/TestListener.java b/src/main/java/com/aventstack/extentreports/TestListener.java
index e526426..5201df4 100644
--- a/src/main/java/com/aventstack/extentreports/TestListener.java
+++ b/src/main/java/com/aventstack/extentreports/TestListener.java
@@ -7,98 +7,90 @@
import com.aventstack.extentreports.model.Device;
import com.aventstack.extentreports.model.Log;
import com.aventstack.extentreports.model.ScreenCapture;
-import com.aventstack.extentreports.model.Screencast;
import com.aventstack.extentreports.model.Test;
/**
* Listener methods invoked when an event occurs in the report:
*
*
- *
A test or node is started
- *
A category or author is added
- *
A media object is added etc.
+ *
A test or node is started
+ *
A category or author is added
+ *
A media object is added etc.
*
*/
public interface TestListener {
-
- /**
- * Invoked when a test is started using createTest()
- *
- * @param test {@link com.aventstack.extentreports.model.Test} object
- */
- void onTestStarted(Test test);
-
- /**
- * Invoked when a test is removed using removeTest()
- *
- * @param test {@link com.aventstack.extentreports.model.Test} object
- */
- void onTestRemoved(Test test);
-
- /**
- * Invoked when a node is started using createNode()
- *
- * @param node {@link com.aventstack.extentreports.model.Test} object
- */
- void onNodeStarted(Test node);
-
- /**
- * Invoked each time a log is added to any test/node
- *
- * @param test {@link com.aventstack.extentreports.model.Test} object
- * @param log {@link com.aventstack.extentreports.model.Log} object
- */
- void onLogAdded(Test test, Log log);
-
- /**
- * Invoked each time a category is assigned to any test/node
- *
- * @param test {@link com.aventstack.extentreports.model.Test} object
- * @param category {@link com.aventstack.extentreports.model.Category} object
- */
- void onCategoryAssigned(Test test, Category category);
-
- /**
- * Invoked each time an author is assigned to any test/node
- *
- * @param test {@link com.aventstack.extentreports.model.Test} object
- * @param author {@link com.aventstack.extentreports.model.Author} object
- */
- void onAuthorAssigned(Test test, Author author);
-
- /**
- * Invoked each time a device is assigned to any test/node
- *
- * @param test {@link com.aventstack.extentreports.model.Test} object
- * @param device {@link com.aventstack.extentreports.model.Device} object
- */
- void onDeviceAssigned(Test test, Device device);
-
- /**
- * Invoked each time a screencapture is added to test
- *
- * @param test {@link com.aventstack.extentreports.model.Test} object
- * @param screenCapture {@link com.aventstack.extentreports.model.ScreenCapture} object
- * @throws IOException Exception thrown if the media object is not found
- */
- void onScreenCaptureAdded(Test test, ScreenCapture screenCapture) throws IOException;
-
- /**
- * Invoked each time a screencapture is added to log
- *
- * @param log {@link com.aventstack.extentreports.model.Log} object
- * @param screenCapture {@link com.aventstack.extentreports.model.ScreenCapture} object
- * @throws IOException Exception thrown if the media object is not found
- */
- void onScreenCaptureAdded(Log log, ScreenCapture screenCapture) throws IOException;
-
- /**
- * Invoked each time a screencast is added
- *
- * @param test {@link com.aventstack.extentreports.model.Test} object
- * @param screencast {@link com.aventstack.extentreports.model.Screencast} object
- * @throws IOException Exception thrown if the media object is not found
- */
- void onScreencastAdded(Test test, Screencast screencast) throws IOException;
-
-}
+
+ /**
+ * Invoked when a test is started using createTest()
+ *
+ * @param test {@link com.aventstack.extentreports.model.Test} object
+ */
+ void onTestStarted(Test test);
+
+ /**
+ * Invoked when a test is removed using removeTest()
+ *
+ * @param test {@link com.aventstack.extentreports.model.Test} object
+ */
+ void onTestRemoved(Test test);
+
+ /**
+ * Invoked when a node is started using createNode()
+ *
+ * @param node {@link com.aventstack.extentreports.model.Test} object
+ */
+ void onNodeStarted(Test node);
+
+ /**
+ * Invoked each time a log is added to any test/node
+ *
+ * @param test {@link com.aventstack.extentreports.model.Test} object
+ * @param log {@link com.aventstack.extentreports.model.Log} object
+ */
+ void onLogAdded(Test test, Log log);
+
+ /**
+ * Invoked each time a category is assigned to any test/node
+ *
+ * @param test {@link com.aventstack.extentreports.model.Test} object
+ * @param category {@link com.aventstack.extentreports.model.Category} object
+ */
+ void onCategoryAssigned(Test test, Category category);
+
+ /**
+ * Invoked each time an author is assigned to any test/node
+ *
+ * @param test {@link com.aventstack.extentreports.model.Test} object
+ * @param author {@link com.aventstack.extentreports.model.Author} object
+ */
+ void onAuthorAssigned(Test test, Author author);
+
+ /**
+ * Invoked each time a device is assigned to any test/node
+ *
+ * @param test {@link com.aventstack.extentreports.model.Test} object
+ * @param device {@link com.aventstack.extentreports.model.Device} object
+ */
+ void onDeviceAssigned(Test test, Device device);
+
+ /**
+ * Invoked each time a screencapture is added to test
+ *
+ * @param test {@link com.aventstack.extentreports.model.Test} object
+ * @param screenCapture {@link com.aventstack.extentreports.model.ScreenCapture}
+ * object
+ * @throws IOException Exception thrown if the media object is not found
+ */
+ void onScreenCaptureAdded(Test test, ScreenCapture screenCapture) throws IOException;
+
+ /**
+ * Invoked each time a screencapture is added to log
+ *
+ * @param log {@link com.aventstack.extentreports.model.Log} object
+ * @param screenCapture {@link com.aventstack.extentreports.model.ScreenCapture}
+ * object
+ * @throws IOException Exception thrown if the media object is not found
+ */
+ void onScreenCaptureAdded(Log log, ScreenCapture screenCapture) throws IOException;
+
+}
\ No newline at end of file
diff --git a/src/main/java/com/aventstack/extentreports/TestRemover.java b/src/main/java/com/aventstack/extentreports/TestRemover.java
deleted file mode 100644
index e442fd2..0000000
--- a/src/main/java/com/aventstack/extentreports/TestRemover.java
+++ /dev/null
@@ -1,66 +0,0 @@
-package com.aventstack.extentreports;
-
-import java.util.List;
-import java.util.stream.Collectors;
-
-import com.aventstack.extentreports.model.Test;
-
-class TestRemover {
-
- /**
- * Helper for removing test recursively. This flag determines when to break
- * out of recursion
- */
- private static boolean removed = false;
-
- private TestRemover() { }
-
- /**
- * Remove a test using its unique ID from a list
- *
- * @param list a list of {@link Test}
- * @param test {@link Test} to be removed
- */
- public static void remove(List testList, Test test) {
- removed = false;
- findAndRemoveTest(testList, test);
- }
-
- /**
- * Recursively traverses all tests, nodes upto the last leaf to find and remove
- * the specified test
- *
- * @param list a list of {@link Test}
- * @param test {@link Test} to be removed
- */
- private static void findAndRemoveTest(List list, Test test) {
- List filteredTestList = list
- .stream()
- .filter(x -> x.getID() == test.getID())
- .collect(Collectors.toList());
-
- if (filteredTestList.size() == 1) {
- removeTest(list, filteredTestList.get(0));
- removed = true;
- return;
- }
-
- for (Test t : list) {
- if (removed) {
- return;
- }
- findAndRemoveTest(t.getNodeContext().getAll(), test);
- }
- }
-
- /**
- * Removes the test from a given list of tests
- *
- * @param list a list of {@link Test}
- * @param test {@link Test} to be removed
- */
- private static void removeTest(List list, Test test) {
- list.remove(test);
- }
-
-}
diff --git a/src/main/java/com/aventstack/extentreports/configuration/ConfigurationBuilder.java b/src/main/java/com/aventstack/extentreports/configuration/ConfigurationBuilder.java
new file mode 100644
index 0000000..c66ec17
--- /dev/null
+++ b/src/main/java/com/aventstack/extentreports/configuration/ConfigurationBuilder.java
@@ -0,0 +1,84 @@
+package com.aventstack.extentreports.configuration;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+
+import org.w3c.dom.CharacterData;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+import org.xml.sax.SAXException;
+
+public class ConfigurationBuilder {
+
+ private static final Logger logger = Logger.getLogger(ConfigurationBuilder.class.getName());
+
+ private ConfigurationStore store = new ConfigurationStore();
+ private InputStream stream;
+
+ public ConfigurationBuilder(URL url) {
+ try {
+ stream = url.openStream();
+ } catch (IOException e) {
+ logger.log(Level.SEVERE, url.toString(), e);
+ }
+ }
+
+ public ConfigurationBuilder(File file, Boolean silent) {
+ try {
+ if (silent && !file.exists())
+ return;
+ stream = new FileInputStream(file);
+ } catch (FileNotFoundException e) {
+ logger.log(Level.SEVERE, file.getPath(), e);
+ }
+ }
+
+ public ConfigurationStore getConfigurationStore() {
+ if (stream == null)
+ return null;
+
+ DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
+ DocumentBuilder documentBuilder;
+ String value;
+
+ try {
+ documentBuilder = documentBuilderFactory.newDocumentBuilder();
+
+ Document doc = documentBuilder.parse(stream);
+ doc.getDocumentElement().normalize();
+
+ NodeList nodeList = doc.getElementsByTagName("configuration").item(0).getChildNodes();
+
+ for (int ix = 0; ix < nodeList.getLength(); ix++) {
+ Node node = nodeList.item(ix);
+
+ Element el = node.getNodeType() == Node.ELEMENT_NODE ? (Element) node : null;
+
+ if (el != null) {
+ value = el.getTextContent();
+
+ value = el instanceof CharacterData ? ((CharacterData) el).getData() : value;
+ store.storeConfig(el.getNodeName(), value);
+ }
+ }
+
+ return store;
+ } catch (IOException | SAXException | ParserConfigurationException e) {
+ logger.log(Level.SEVERE, "Failed to load external configuration", e);
+ }
+
+ return null;
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/aventstack/extentreports/configuration/ConfigurationStore.java b/src/main/java/com/aventstack/extentreports/configuration/ConfigurationStore.java
new file mode 100644
index 0000000..51e2acb
--- /dev/null
+++ b/src/main/java/com/aventstack/extentreports/configuration/ConfigurationStore.java
@@ -0,0 +1,43 @@
+package com.aventstack.extentreports.configuration;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public class ConfigurationStore {
+
+ private Map store = new HashMap();
+
+ public Map getStore() {
+ return store;
+ }
+
+ public void storeConfig(String key, Object value) {
+ store.put(key, value);
+ }
+
+ public boolean containsConfig(String k) {
+ return store.containsKey(k);
+ }
+
+ public void removeConfig(String k) {
+ store.remove(k);
+ }
+
+ public Object getConfig(String k) {
+ return store.containsKey(k) ? store.get(k) : null;
+ }
+
+ public void extendConfig(Map map) {
+ map.forEach((key, value) -> this.storeConfig(key, value));
+ }
+
+ public void extendConfig(ConfigurationStore config) {
+ Map map = config.store;
+ this.extendConfig(map);
+ }
+
+ public boolean isEmpty() {
+ return store.isEmpty();
+ }
+
+}
diff --git a/src/main/java/com/aventstack/extentreports/convert/JsonDeserializer.java b/src/main/java/com/aventstack/extentreports/convert/JsonDeserializer.java
new file mode 100644
index 0000000..669f6d0
--- /dev/null
+++ b/src/main/java/com/aventstack/extentreports/convert/JsonDeserializer.java
@@ -0,0 +1,24 @@
+package com.aventstack.extentreports.convert;
+
+import java.io.File;
+import java.io.IOException;
+import java.lang.reflect.Type;
+import java.nio.file.Files;
+import java.util.ArrayList;
+import java.util.List;
+
+import com.aventstack.extentreports.model.Test;
+import com.google.gson.Gson;
+import com.google.gson.reflect.TypeToken;
+
+class JsonDeserializer {
+
+ public static List deserialize(File f) throws IOException {
+ Gson gson = new Gson();
+ String json = new String(Files.readAllBytes(f.toPath()));
+ Type t = new TypeToken>() {}.getType();
+ List tests = gson.fromJson(json, t);
+ return tests;
+ }
+
+}
diff --git a/src/main/java/com/aventstack/extentreports/convert/TestModelReportBuilder.java b/src/main/java/com/aventstack/extentreports/convert/TestModelReportBuilder.java
new file mode 100644
index 0000000..eeef8a9
--- /dev/null
+++ b/src/main/java/com/aventstack/extentreports/convert/TestModelReportBuilder.java
@@ -0,0 +1,71 @@
+package com.aventstack.extentreports.convert;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.List;
+
+import com.aventstack.extentreports.ExtentReports;
+import com.aventstack.extentreports.ExtentTest;
+import com.aventstack.extentreports.GherkinKeyword;
+import com.aventstack.extentreports.model.Log;
+import com.aventstack.extentreports.model.Test;
+
+public class TestModelReportBuilder {
+
+ public void createDomainFromJsonArchive(ExtentReports extent, File jsonFile) throws IOException {
+ if (!jsonFile.exists()) {
+ return;
+ }
+ Boolean configChanged = extent.getReportUsesManualConfiguration() ? false : true;
+ extent.setReportUsesManualConfiguration(true);
+ List tests = JsonDeserializer.deserialize(jsonFile);
+ for (Test test : tests) {
+ try {
+ if (test.getBehaviorDrivenTypeName() == null) {
+ createDomain(test, extent.createTest(test.getName(), test.getDescription()));
+ } else {
+ createDomain(test, extent.createTest(new GherkinKeyword(test.getBehaviorDrivenTypeName()),
+ test.getName(), test.getDescription()));
+
+ }
+ } catch (ClassNotFoundException e) {
+ e.printStackTrace();
+ }
+ }
+ if (configChanged) {
+ extent.setReportUsesManualConfiguration(false);
+ }
+ }
+
+ public void createDomain(Test test, ExtentTest extentTest) throws ClassNotFoundException {
+ extentTest.getModel().setStartTime(test.getStartTime());
+ extentTest.getModel().setEndTime(test.getEndTime());
+ extentTest.getModel().computeEndTimeFromChildren();
+
+ // create events
+ for (Log log : test.getLogContext().getAll()) {
+ if (log.getDetails() != null)
+ extentTest.log(log.getStatus(), log.getDetails());
+ if (log.getExceptionInfo() != null)
+ extentTest.log(log.getStatus(), log.getExceptionInfo());
+ }
+
+ // assign attributes
+ test.getAuthorContext().getAll().forEach(x -> extentTest.assignAuthor(x.getName()));
+ test.getCategoryContext().getAll().forEach(x -> extentTest.assignCategory(x.getName()));
+ test.getDeviceContext().getAll().forEach(x -> extentTest.assignDevice(x.getName()));
+
+ // handle nodes
+ for (Test node : test.getNodeContext().getAll()) {
+ ExtentTest extentNode = null;
+ if (node.getBehaviorDrivenTypeName() == null) {
+ extentNode = extentTest.createNode(node.getName(), node.getDescription());
+ } else {
+ extentNode = extentTest.createNode(new GherkinKeyword(node.getBehaviorDrivenTypeName()), node.getName(),
+ node.getDescription());
+ }
+ createDomain(node, extentNode);
+ }
+ }
+
+}
diff --git a/src/main/java/com/aventstack/extentreports/exceptions/ExtentTestInterruptedException.java b/src/main/java/com/aventstack/extentreports/exceptions/ExtentTestInterruptedException.java
deleted file mode 100644
index fda727b..0000000
--- a/src/main/java/com/aventstack/extentreports/exceptions/ExtentTestInterruptedException.java
+++ /dev/null
@@ -1,17 +0,0 @@
-package com.aventstack.extentreports.exceptions;
-
-@SuppressWarnings("serial")
-public class ExtentTestInterruptedException extends RuntimeException {
- public ExtentTestInterruptedException(Throwable t) {
- super(t);
- }
-
- public ExtentTestInterruptedException(String string) {
- super(string);
- }
-
- public ExtentTestInterruptedException(String string, Throwable t) {
- super(string, t);
- }
-
-}
diff --git a/src/main/java/com/aventstack/extentreports/exceptions/InvalidFileException.java b/src/main/java/com/aventstack/extentreports/exceptions/InvalidFileException.java
deleted file mode 100644
index 4cf981b..0000000
--- a/src/main/java/com/aventstack/extentreports/exceptions/InvalidFileException.java
+++ /dev/null
@@ -1,21 +0,0 @@
-package com.aventstack.extentreports.exceptions;
-
-@SuppressWarnings("serial")
-public class InvalidFileException extends Exception {
- public InvalidFileException() {
- super();
- }
-
- public InvalidFileException(Throwable t) {
- super(t);
- }
-
- public InvalidFileException(String string) {
- super(string);
- }
-
- public InvalidFileException(String string, Throwable t) {
- super(string, t);
- }
-
-}
diff --git a/src/main/java/com/aventstack/extentreports/externalconfig/ConfigLoader.java b/src/main/java/com/aventstack/extentreports/externalconfig/ConfigLoader.java
deleted file mode 100644
index e9be842..0000000
--- a/src/main/java/com/aventstack/extentreports/externalconfig/ConfigLoader.java
+++ /dev/null
@@ -1,107 +0,0 @@
-package com.aventstack.extentreports.externalconfig;
-
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileNotFoundException;
-import java.io.IOException;
-import java.io.InputStream;
-import java.net.URL;
-import java.util.logging.Level;
-import java.util.logging.Logger;
-
-import javax.xml.parsers.DocumentBuilder;
-import javax.xml.parsers.DocumentBuilderFactory;
-import javax.xml.parsers.ParserConfigurationException;
-
-import org.w3c.dom.CharacterData;
-import org.w3c.dom.Document;
-import org.w3c.dom.Element;
-import org.w3c.dom.Node;
-import org.w3c.dom.NodeList;
-import org.xml.sax.SAXException;
-
-import com.aventstack.extentreports.externalconfig.model.Config;
-import com.aventstack.extentreports.externalconfig.model.ConfigMap;
-
-public class ConfigLoader {
-
- private static final Logger logger = Logger.getLogger(ConfigLoader.class.getName());
-
- private ConfigMap configContext;
- private InputStream stream;
-
- ConfigLoader() {
- configContext = new ConfigMap();
- }
-
- public ConfigLoader(URL url) {
- this();
-
- try {
- stream = url.openStream();
- }
- catch (IOException e) {
- logger.log(Level.SEVERE, url.toString(), e);
- }
- }
-
- public ConfigLoader(File file, Boolean silent) {
- this();
-
- try {
- if (silent && !file.exists())
- return;
- stream = new FileInputStream(file);
- }
- catch (FileNotFoundException e) {
- logger.log(Level.SEVERE, file.getPath(), e);
- }
- }
-
- public ConfigMap getConfigurationHash() {
- if (stream == null)
- return null;
-
- DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
- DocumentBuilder dBuilder;
- String value;
-
- try {
- dBuilder = dbFactory.newDocumentBuilder();
-
- Document doc = dBuilder.parse(stream);
- doc.getDocumentElement().normalize();
-
- NodeList nodeList = doc.getElementsByTagName("configuration").item(0).getChildNodes();
-
- for (int ix = 0; ix < nodeList.getLength(); ix++) {
- Node node = nodeList.item(ix);
-
- Element el = node.getNodeType() == Node.ELEMENT_NODE
- ? (Element) node
- : null;
-
- if (el != null) {
- value = el.getTextContent();
-
- value = el instanceof CharacterData
- ? ((CharacterData) el).getData()
- : value;
-
- Config c = new Config();
- c.setKey(el.getNodeName());
- c.setValue(value);
-
- configContext.setConfig(c);
- }
- }
-
- return configContext;
- }
- catch (IOException|SAXException|ParserConfigurationException e) {
- logger.log(Level.SEVERE, "Config", e);
- }
-
- return null;
- }
-}
diff --git a/src/main/java/com/aventstack/extentreports/externalconfig/model/Config.java b/src/main/java/com/aventstack/extentreports/externalconfig/model/Config.java
deleted file mode 100644
index e1d34dc..0000000
--- a/src/main/java/com/aventstack/extentreports/externalconfig/model/Config.java
+++ /dev/null
@@ -1,23 +0,0 @@
-package com.aventstack.extentreports.externalconfig.model;
-
-public class Config {
-
- private String k;
- private Object v;
-
- public void setKey(String k) {
- this.k = k;
- }
-
- public String getKey() {
- return k;
- }
-
- public void setValue(Object v) {
- this.v = v;
- }
-
- public Object getValue() {
- return v;
- }
-}
diff --git a/src/main/java/com/aventstack/extentreports/externalconfig/model/ConfigMap.java b/src/main/java/com/aventstack/extentreports/externalconfig/model/ConfigMap.java
deleted file mode 100644
index 258a669..0000000
--- a/src/main/java/com/aventstack/extentreports/externalconfig/model/ConfigMap.java
+++ /dev/null
@@ -1,43 +0,0 @@
-package com.aventstack.extentreports.externalconfig.model;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Optional;
-
-public class ConfigMap {
-
- private List configList;
-
- public ConfigMap() {
- configList = new ArrayList<>();
- }
-
- public void setConfig(Config c) {
- if (containsKey(c.getKey()))
- removeKey(c.getKey());
-
- configList.add(c);
- }
-
- public List getConfigList() { return configList; }
-
- public boolean containsKey(String k) {
- return configList.stream()
- .anyMatch(x -> x.getKey().equals(k));
- }
-
- void removeKey(String k) {
- configList.removeIf(x -> x.getKey().equals(k));
- }
-
- public Object getValue(String k) {
- Optional c = configList.stream()
- .filter(x -> x.getKey().equals(k))
- .findFirst();
-
- if (c.isPresent())
- return c.get().getValue();
-
- return null;
- }
-}
diff --git a/src/main/java/com/aventstack/extentreports/gherkin/GherkinDialect.java b/src/main/java/com/aventstack/extentreports/gherkin/GherkinDialect.java
index 974510e..37b51a5 100644
--- a/src/main/java/com/aventstack/extentreports/gherkin/GherkinDialect.java
+++ b/src/main/java/com/aventstack/extentreports/gherkin/GherkinDialect.java
@@ -5,7 +5,7 @@
/**
*
- * Modified version of GherkinKeyword.java from cucumber/gherkin. Source url:
+ * Modified version of GherkinKeyword.java from cucumber/gherkin. Source url:
* https://raw.githubusercontent.com/cucumber/cucumber/master/gherkin/java/src/main/java/gherkin/GherkinDialect.java
*
*
@@ -13,21 +13,23 @@
*
*/
public class GherkinDialect {
- private final Map> keywords;
- private String language;
+
+ private final Map> keywords;
+ private String language;
- public GherkinDialect(String language, Map> keywords) {
- this.language = language;
- this.keywords = keywords;
- }
+ public GherkinDialect(String language, Map> keywords) {
+ keywords.remove("name");
+ keywords.remove("native");
+ this.language = language;
+ this.keywords = keywords;
+ }
- public Map> getKeywords() {
- keywords.remove("name");
- keywords.remove("native");
- return keywords;
- }
+ public Map> getKeywords() {
+ return keywords;
+ }
- public String getLanguage() {
- return language;
- }
+ public String getLanguage() {
+ return language;
+ }
+
}
\ No newline at end of file
diff --git a/src/main/java/com/aventstack/extentreports/gherkin/GherkinDialectProvider.java b/src/main/java/com/aventstack/extentreports/gherkin/GherkinDialectProvider.java
index 32c815b..4cc01cc 100644
--- a/src/main/java/com/aventstack/extentreports/gherkin/GherkinDialectProvider.java
+++ b/src/main/java/com/aventstack/extentreports/gherkin/GherkinDialectProvider.java
@@ -10,7 +10,8 @@
/**
*
- * Modified version of GherkinDialectProvider.java from cucumber/gherkin. Source url:
+ * Modified version of GherkinDialectProvider.java from cucumber/gherkin. Source
+ * url:
* https://github.com/cucumber/cucumber/blob/master/gherkin/java/src/main/java/gherkin/GherkinDialectProvider.java.
*
*
@@ -20,54 +21,57 @@
@SuppressWarnings("unchecked")
public class GherkinDialectProvider {
- private static final String DEFAULT_LANGUAGE = "en";
- private static final String GHERKIN_LANGUAGES_JSON_URL = "https://github.com/cucumber/cucumber/blob/master/gherkin/java/src/main/resources/gherkin/gherkin-languages.json";
-
- private static GherkinDialect currentDialect;
- private static Map>> dialects;
- private static String language;
-
- static {
- Gson gson = new Gson();
- try {
- Reader d = new InputStreamReader(GherkinDialectProvider.class.getResourceAsStream("gherkin-languages.json"), "UTF-8");
- dialects = gson.fromJson(d, Map.class);
- } catch (UnsupportedEncodingException e) {
- throw new RuntimeException(e);
- }
- }
-
- public static GherkinDialect getDialect() {
- return currentDialect;
- }
-
- public static String getDefaultLanguage() {
- return DEFAULT_LANGUAGE;
- }
-
- public static String getLanguage() {
- if (language == null || language.isEmpty())
- language = DEFAULT_LANGUAGE;
-
- return language;
- }
-
- /**
- * Sets/changes the default language
- *
- * @param lang A valid dialect from
- * gherkin-languages.json
- *
- * @throws UnsupportedEncodingException Thrown if the language is one of the supported language from
- * gherkin-languages.json
- */
- public static void setLanguage(String lang) throws UnsupportedEncodingException {
- language = lang;
- Map> map = dialects.get(GherkinDialectProvider.language);
- if (map == null)
- throw new UnsupportedEncodingException("Invalid language [" + language + "]. See list of supported languages: " + GHERKIN_LANGUAGES_JSON_URL);
-
- currentDialect = new GherkinDialect(language, map);
- }
-
+ private static final String DEFAULT_LANGUAGE = "en";
+ private static final String GHERKIN_LANGUAGES_JSON_URL = "https://github.com/cucumber/cucumber/blob/master/gherkin/gherkin-languages.json";
+ private static final String GHERKIN_LANGUAGES_PATH = "gherkin-languages.json";
+
+ private static GherkinDialect currentDialect;
+ private static Map>> dialects;
+ private static String language;
+
+ static {
+ Gson gson = new Gson();
+ try {
+ Reader d = new InputStreamReader(GherkinDialectProvider.class.getResourceAsStream(GHERKIN_LANGUAGES_PATH),
+ "UTF-8");
+ dialects = gson.fromJson(d, Map.class);
+ } catch (UnsupportedEncodingException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ public static GherkinDialect getDialect() {
+ return currentDialect;
+ }
+
+ public static String getDefaultLanguage() {
+ return DEFAULT_LANGUAGE;
+ }
+
+ public static String getLanguage() {
+ if (language == null || language.isEmpty()) {
+ language = DEFAULT_LANGUAGE;
+ }
+ return language;
+ }
+
+ /**
+ * Sets/changes the default language
+ *
+ * @param lang A valid dialect from
+ * https://github.com/cucumber/cucumber/blob/master/gherkin/gherkin-languages.json
+ *
+ * @throws UnsupportedEncodingException Thrown if the language is one of the
+ * supported language from
+ * https://github.com/cucumber/cucumber/blob/master/gherkin/gherkin-languages.json
+ */
+ public static void setLanguage(String lang) throws UnsupportedEncodingException {
+ language = lang;
+ Map> map = dialects.get(GherkinDialectProvider.language);
+ if (map == null) {
+ throw new UnsupportedEncodingException("Invalid language [" + language + "]. See list of supported languages: " + GHERKIN_LANGUAGES_JSON_URL);
+ }
+ currentDialect = new GherkinDialect(language, map);
+ }
+
}
\ No newline at end of file
diff --git a/src/main/java/com/aventstack/extentreports/gherkin/model/And.java b/src/main/java/com/aventstack/extentreports/gherkin/model/And.java
index fdf6983..c2a2bff 100644
--- a/src/main/java/com/aventstack/extentreports/gherkin/model/And.java
+++ b/src/main/java/com/aventstack/extentreports/gherkin/model/And.java
@@ -2,19 +2,18 @@
import java.io.Serializable;
-public class And
- implements IGherkinFormatterModel, Serializable {
+public class And implements IGherkinFormatterModel, Serializable {
private static final long serialVersionUID = 8543289653944756660L;
private static final String VALUE = "And";
-
+
public static String getGherkinName() {
return VALUE;
}
-
+
@Override
public String toString() {
return getGherkinName();
}
-
+
}
diff --git a/src/main/java/com/aventstack/extentreports/gherkin/model/Asterisk.java b/src/main/java/com/aventstack/extentreports/gherkin/model/Asterisk.java
index 05fe3af..c6e10d7 100644
--- a/src/main/java/com/aventstack/extentreports/gherkin/model/Asterisk.java
+++ b/src/main/java/com/aventstack/extentreports/gherkin/model/Asterisk.java
@@ -2,19 +2,18 @@
import java.io.Serializable;
-public class Asterisk
- implements IGherkinFormatterModel, Serializable {
+public class Asterisk implements IGherkinFormatterModel, Serializable {
private static final long serialVersionUID = 7251419811428200133L;
private static final String VALUE = "*";
-
+
public static String getGherkinName() {
return VALUE;
}
-
+
@Override
public String toString() {
return getGherkinName();
}
-
+
}
diff --git a/src/main/java/com/aventstack/extentreports/gherkin/model/Background.java b/src/main/java/com/aventstack/extentreports/gherkin/model/Background.java
index e646aaa..1e42713 100644
--- a/src/main/java/com/aventstack/extentreports/gherkin/model/Background.java
+++ b/src/main/java/com/aventstack/extentreports/gherkin/model/Background.java
@@ -2,19 +2,18 @@
import java.io.Serializable;
-public class Background
- implements IGherkinFormatterModel, Serializable {
+public class Background implements IGherkinFormatterModel, Serializable {
private static final long serialVersionUID = -955371501488725151L;
private static final String VALUE = "Background";
-
+
public static String getGherkinName() {
return VALUE;
}
-
+
@Override
public String toString() {
return getGherkinName();
}
-
+
}
diff --git a/src/main/java/com/aventstack/extentreports/gherkin/model/But.java b/src/main/java/com/aventstack/extentreports/gherkin/model/But.java
index c7f66b6..6d88158 100644
--- a/src/main/java/com/aventstack/extentreports/gherkin/model/But.java
+++ b/src/main/java/com/aventstack/extentreports/gherkin/model/But.java
@@ -2,19 +2,18 @@
import java.io.Serializable;
-public class But
- implements IGherkinFormatterModel, Serializable {
+public class But implements IGherkinFormatterModel, Serializable {
private static final long serialVersionUID = 3420514631996827220L;
private static final String VALUE = "But";
-
+
public static String getGherkinName() {
return VALUE;
}
-
+
@Override
public String toString() {
return getGherkinName();
}
-
+
}
diff --git a/src/main/java/com/aventstack/extentreports/gherkin/model/Feature.java b/src/main/java/com/aventstack/extentreports/gherkin/model/Feature.java
index 4d55c8b..6475396 100644
--- a/src/main/java/com/aventstack/extentreports/gherkin/model/Feature.java
+++ b/src/main/java/com/aventstack/extentreports/gherkin/model/Feature.java
@@ -2,19 +2,18 @@
import java.io.Serializable;
-public class Feature
- implements IGherkinFormatterModel, Serializable {
+public class Feature implements IGherkinFormatterModel, Serializable {
private static final long serialVersionUID = -4719215211721789414L;
private static final String VALUE = "Feature";
-
+
public static String getGherkinName() {
return VALUE;
}
-
+
@Override
public String toString() {
return getGherkinName();
}
-
+
}
diff --git a/src/main/java/com/aventstack/extentreports/gherkin/model/GherkinModelSerializer.java b/src/main/java/com/aventstack/extentreports/gherkin/model/GherkinModelSerializer.java
new file mode 100644
index 0000000..242fefa
--- /dev/null
+++ b/src/main/java/com/aventstack/extentreports/gherkin/model/GherkinModelSerializer.java
@@ -0,0 +1,23 @@
+package com.aventstack.extentreports.gherkin.model;
+
+import java.io.IOException;
+
+import com.google.gson.TypeAdapter;
+import com.google.gson.stream.JsonReader;
+import com.google.gson.stream.JsonWriter;
+
+public class GherkinModelSerializer extends TypeAdapter {
+
+ @Override
+ public void write(JsonWriter out, IGherkinFormatterModel value) throws IOException {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public IGherkinFormatterModel read(JsonReader in) throws IOException {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+}
diff --git a/src/main/java/com/aventstack/extentreports/gherkin/model/Given.java b/src/main/java/com/aventstack/extentreports/gherkin/model/Given.java
index 5ac6eca..483b0d2 100644
--- a/src/main/java/com/aventstack/extentreports/gherkin/model/Given.java
+++ b/src/main/java/com/aventstack/extentreports/gherkin/model/Given.java
@@ -2,19 +2,18 @@
import java.io.Serializable;
-public class Given
- implements IGherkinFormatterModel, Serializable {
+public class Given implements IGherkinFormatterModel, Serializable {
private static final long serialVersionUID = 939197985263690070L;
private static final String VALUE = "Given";
-
+
public static String getGherkinName() {
return VALUE;
}
-
+
@Override
public String toString() {
return getGherkinName();
}
-
+
}
diff --git a/src/main/java/com/aventstack/extentreports/gherkin/model/IGherkinFormatterModel.java b/src/main/java/com/aventstack/extentreports/gherkin/model/IGherkinFormatterModel.java
index d9b3a0e..d150968 100644
--- a/src/main/java/com/aventstack/extentreports/gherkin/model/IGherkinFormatterModel.java
+++ b/src/main/java/com/aventstack/extentreports/gherkin/model/IGherkinFormatterModel.java
@@ -2,5 +2,5 @@
import java.io.Serializable;
-public interface IGherkinFormatterModel
- extends Serializable { }
+public interface IGherkinFormatterModel extends Serializable {
+}
diff --git a/src/main/java/com/aventstack/extentreports/gherkin/model/Scenario.java b/src/main/java/com/aventstack/extentreports/gherkin/model/Scenario.java
index 8f85f55..683f4d1 100644
--- a/src/main/java/com/aventstack/extentreports/gherkin/model/Scenario.java
+++ b/src/main/java/com/aventstack/extentreports/gherkin/model/Scenario.java
@@ -2,19 +2,18 @@
import java.io.Serializable;
-public class Scenario
- implements IGherkinFormatterModel, Serializable {
+public class Scenario implements IGherkinFormatterModel, Serializable {
private static final long serialVersionUID = 7401124129196617280L;
private static final String VALUE = "Scenario";
-
+
public static String getGherkinName() {
return VALUE;
}
-
+
@Override
public String toString() {
return getGherkinName();
}
-
+
}
diff --git a/src/main/java/com/aventstack/extentreports/gherkin/model/ScenarioOutline.java b/src/main/java/com/aventstack/extentreports/gherkin/model/ScenarioOutline.java
index 481c890..6b84733 100644
--- a/src/main/java/com/aventstack/extentreports/gherkin/model/ScenarioOutline.java
+++ b/src/main/java/com/aventstack/extentreports/gherkin/model/ScenarioOutline.java
@@ -2,19 +2,18 @@
import java.io.Serializable;
-public class ScenarioOutline
- implements IGherkinFormatterModel, Serializable {
+public class ScenarioOutline implements IGherkinFormatterModel, Serializable {
private static final long serialVersionUID = -2058398543903906031L;
private static final String VALUE = "Scenario Outline";
-
+
public static String getGherkinName() {
return VALUE;
}
-
+
@Override
public String toString() {
return getGherkinName();
}
-
+
}
diff --git a/src/main/java/com/aventstack/extentreports/gherkin/model/Then.java b/src/main/java/com/aventstack/extentreports/gherkin/model/Then.java
index 427a738..2ad2bc7 100644
--- a/src/main/java/com/aventstack/extentreports/gherkin/model/Then.java
+++ b/src/main/java/com/aventstack/extentreports/gherkin/model/Then.java
@@ -2,19 +2,18 @@
import java.io.Serializable;
-public class Then
- implements IGherkinFormatterModel, Serializable {
+public class Then implements IGherkinFormatterModel, Serializable {
private static final long serialVersionUID = 2493591502473169772L;
private static final String VALUE = "Then";
-
+
public static String getGherkinName() {
return VALUE;
}
-
+
@Override
public String toString() {
return getGherkinName();
}
-
+
}
diff --git a/src/main/java/com/aventstack/extentreports/gherkin/model/When.java b/src/main/java/com/aventstack/extentreports/gherkin/model/When.java
index 5da0d15..d9460db 100644
--- a/src/main/java/com/aventstack/extentreports/gherkin/model/When.java
+++ b/src/main/java/com/aventstack/extentreports/gherkin/model/When.java
@@ -2,19 +2,18 @@
import java.io.Serializable;
-public class When
- implements IGherkinFormatterModel, Serializable {
+public class When implements IGherkinFormatterModel, Serializable {
private static final long serialVersionUID = 8337259741948416898L;
private static final String VALUE = "When";
-
+
public static String getGherkinName() {
return VALUE;
}
-
+
@Override
public String toString() {
return getGherkinName();
}
-
+
}
diff --git a/src/main/java/com/aventstack/extentreports/io/FileWriterBuffered.java b/src/main/java/com/aventstack/extentreports/io/FileWriterBuffered.java
new file mode 100644
index 0000000..76b1bcb
--- /dev/null
+++ b/src/main/java/com/aventstack/extentreports/io/FileWriterBuffered.java
@@ -0,0 +1,35 @@
+package com.aventstack.extentreports.io;
+
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileWriter;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+public class FileWriterBuffered {
+
+ private static class WriterInstance {
+ static final FileWriterBuffered INSTANCE = new FileWriterBuffered();
+
+ private WriterInstance() {
+ }
+ }
+
+ static final Logger logger = Logger.getLogger(FileWriterBuffered.class.getName());
+
+ private FileWriterBuffered() {
+ }
+
+ public synchronized void write(final File f, String text) {
+ try (BufferedWriter writer = new BufferedWriter(new FileWriter(f))) {
+ writer.write(text);
+ } catch (Exception e) {
+ logger.log(Level.SEVERE, f.getPath(), e);
+ }
+ }
+
+ public static FileWriterBuffered getInstance() {
+ return WriterInstance.INSTANCE;
+ }
+
+}
\ No newline at end of file
diff --git a/src/main/java/com/aventstack/extentreports/io/ResourceUtil.java b/src/main/java/com/aventstack/extentreports/io/ResourceUtil.java
new file mode 100644
index 0000000..6069081
--- /dev/null
+++ b/src/main/java/com/aventstack/extentreports/io/ResourceUtil.java
@@ -0,0 +1,54 @@
+package com.aventstack.extentreports.io;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URI;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.nio.file.StandardCopyOption;
+
+public class ResourceUtil {
+
+ public static void moveResource(String resourcePath, String copyPath) {
+ if (copyPath != null)
+ copyPath = copyPath.replace("\\", "/");
+ if (resourcePath != null)
+ resourcePath = resourcePath.replace("\\", "/");
+
+ try {
+ ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
+ InputStream in = classLoader.getResourceAsStream(resourcePath);
+
+ FileOutputStream out = new FileOutputStream(copyPath);
+
+ byte[] b = new byte[1024];
+ int noOfBytes = 0;
+
+ while ((noOfBytes = in.read(b)) != -1) {
+ out.write(b, 0, noOfBytes);
+ }
+
+ in.close();
+ out.close();
+ } catch (FileNotFoundException e) {
+ e.printStackTrace();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+
+ public static void moveBinaryFile(String resourcePath, String copyPath) {
+ URI uri = new File(resourcePath).toURI();
+ Path path = Paths.get(uri);
+ try {
+ Files.copy(path, new File(copyPath).toPath(), StandardCopyOption.REPLACE_EXISTING);
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/src/main/java/com/aventstack/extentreports/markuputils/CodeBlock.java b/src/main/java/com/aventstack/extentreports/markuputils/CodeBlock.java
index ea8a18a..d378816 100644
--- a/src/main/java/com/aventstack/extentreports/markuputils/CodeBlock.java
+++ b/src/main/java/com/aventstack/extentreports/markuputils/CodeBlock.java
@@ -1,43 +1,65 @@
package com.aventstack.extentreports.markuputils;
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;
-class CodeBlock implements Markup {
-
- private static final long serialVersionUID = -5532095355983830164L;
-
- private static final AtomicInteger id = new AtomicInteger(0);
-
- private String code;
- private CodeLanguage lang;
-
- public void setCodeBlock(String code) {
- this.code = code;
- }
- public String getCodeBlock() {
- return code;
- }
-
- public void setCodeBlock(String code, CodeLanguage lang) {
- this.code = code;
- this.lang = lang;
- }
-
- @Override
- public String getMarkup() {
- if (lang == CodeLanguage.JSON) {
- int index = id.getAndIncrement();
- return "" +
- "";
- }
-
- String lhs = "";
-
- return lhs + code + rhs;
- }
+import freemarker.template.Template;
+import freemarker.template.TemplateException;
+
+class CodeBlock extends MarkupTemplate implements Markup {
+
+ private static final long serialVersionUID = -5532095355983830164L;
+ private static final AtomicInteger id = new AtomicInteger(0);
+ private static final String CODEBLOCK_TEMPLATE = "codeblock.ftl";
+ private static final String CODEBLOCK_JSON_TEMPLATE = "codeblock.json.ftl";
+ private static Template codeblock;
+ private static Template codeblockJson;
+ private String code;
+ private CodeLanguage lang;
+
+ static {
+ try {
+ codeblock = ft.createTemplate(CODEBLOCK_TEMPLATE);
+ codeblockJson = ft.createTemplate(CODEBLOCK_JSON_TEMPLATE);
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ public void setCodeBlock(String code) {
+ this.code = code;
+ }
+
+ public String getCodeBlock() {
+ return code;
+ }
+
+ public void setCodeBlock(String code, CodeLanguage lang) {
+ this.code = code;
+ this.lang = lang;
+ }
+
+ @Override
+ public String getMarkup() {
+ int index = 0;
+ Template t = codeblock;
+ if (lang == CodeLanguage.JSON) {
+ index = id.getAndIncrement();
+ t = codeblockJson;
+ }
+ Map map = new HashMap<>();
+ map.put("code", code);
+ map.put("index", index);
+ try {
+ return ft.getSource(t, map);
+ } catch (TemplateException e) {
+ e.printStackTrace();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ return null;
+ }
}
diff --git a/src/main/java/com/aventstack/extentreports/markuputils/Markup.java b/src/main/java/com/aventstack/extentreports/markuputils/Markup.java
index ff0a803..bd8856c 100644
--- a/src/main/java/com/aventstack/extentreports/markuputils/Markup.java
+++ b/src/main/java/com/aventstack/extentreports/markuputils/Markup.java
@@ -4,5 +4,5 @@
@FunctionalInterface
public interface Markup extends Serializable {
- String getMarkup();
+ String getMarkup();
}
diff --git a/src/main/java/com/aventstack/extentreports/markuputils/MarkupHelper.java b/src/main/java/com/aventstack/extentreports/markuputils/MarkupHelper.java
index 92a12a5..42ca33d 100644
--- a/src/main/java/com/aventstack/extentreports/markuputils/MarkupHelper.java
+++ b/src/main/java/com/aventstack/extentreports/markuputils/MarkupHelper.java
@@ -1,30 +1,30 @@
package com.aventstack.extentreports.markuputils;
public class MarkupHelper {
-
- public static Markup createLabel(String text, ExtentColor color) {
- Label l = new Label();
- l.setText(text);
- l.setColor(color);
- return l;
- }
-
- public static Markup createCodeBlock(String code) {
- CodeBlock cb = new CodeBlock();
- cb.setCodeBlock(code);
- return cb;
- }
-
- public static Markup createCodeBlock(String code, CodeLanguage lang) {
- CodeBlock cb = new CodeBlock();
- cb.setCodeBlock(code, lang);
- return cb;
- }
-
- public static Markup createTable(String[][] data) {
- Table t = new Table();
- t.setData(data);
- return t;
- }
-
+
+ public static Markup createLabel(String text, ExtentColor color) {
+ Label l = new Label();
+ l.setText(text);
+ l.setColor(color);
+ return l;
+ }
+
+ public static Markup createCodeBlock(String code) {
+ CodeBlock cb = new CodeBlock();
+ cb.setCodeBlock(code);
+ return cb;
+ }
+
+ public static Markup createCodeBlock(String code, CodeLanguage lang) {
+ CodeBlock cb = new CodeBlock();
+ cb.setCodeBlock(code, lang);
+ return cb;
+ }
+
+ public static Markup createTable(String[][] data) {
+ Table t = new Table();
+ t.setData(data);
+ return t;
+ }
+
}
diff --git a/src/main/java/com/aventstack/extentreports/markuputils/MarkupTemplate.java b/src/main/java/com/aventstack/extentreports/markuputils/MarkupTemplate.java
new file mode 100644
index 0000000..f5db943
--- /dev/null
+++ b/src/main/java/com/aventstack/extentreports/markuputils/MarkupTemplate.java
@@ -0,0 +1,10 @@
+package com.aventstack.extentreports.markuputils;
+
+import com.aventstack.extentreports.ExtentReports;
+import com.aventstack.extentreports.templating.FreemarkerTemplate;
+
+class MarkupTemplate {
+
+ protected static final FreemarkerTemplate ft = new FreemarkerTemplate(ExtentReports.class, "markup/", "UTF-8");
+
+}
diff --git a/src/main/java/com/aventstack/extentreports/mediastorage/KlovMediaStorageHandler.java b/src/main/java/com/aventstack/extentreports/mediastorage/KlovMediaStorageHandler.java
index c1e25a9..b233c44 100644
--- a/src/main/java/com/aventstack/extentreports/mediastorage/KlovMediaStorageHandler.java
+++ b/src/main/java/com/aventstack/extentreports/mediastorage/KlovMediaStorageHandler.java
@@ -30,9 +30,11 @@ public void saveScreenCapture(BasicMongoReportElement el, ScreenCapture media) t
Document doc = new Document("project", klovMedia.getProjectId())
.append("report", klovMedia.getReportId())
.append("sequence", media.getSequence())
- .append("mediaType", media.getMediaType().toString().toLowerCase())
- .append("test", media.getTestObjectId());
+ .append("test", media.getBsonId().get("testId"));
+ if (media.isBase64()) {
+ doc.append("base64String", media.getBase64String());
+ }
if (el.getClass() != Test.class) {
doc.append("log", el.getObjectId());
} else {
@@ -41,9 +43,8 @@ public void saveScreenCapture(BasicMongoReportElement el, ScreenCapture media) t
klovMedia.getMediaCollection().insertOne(doc);
ObjectId mediaId = MongoUtil.getId(doc);
- media.setObjectId(mediaId);
-
- media.setReportObjectId(klovMedia.getReportId());
+ media.getBsonId().put("id", mediaId);
+ media.getBsonId().put("reportId", klovMedia.getReportId());
mediaStorage.storeMedia((ScreenCapture)media);
}
diff --git a/src/main/java/com/aventstack/extentreports/mediastorage/impl/HttpMediaManagerImplKlov.java b/src/main/java/com/aventstack/extentreports/mediastorage/impl/HttpMediaManagerImplKlov.java
index 043777a..a671248 100644
--- a/src/main/java/com/aventstack/extentreports/mediastorage/impl/HttpMediaManagerImplKlov.java
+++ b/src/main/java/com/aventstack/extentreports/mediastorage/impl/HttpMediaManagerImplKlov.java
@@ -16,6 +16,7 @@
import com.aventstack.extentreports.mediastorage.MediaStorage;
import com.aventstack.extentreports.model.Media;
+import com.aventstack.extentreports.model.ScreenCapture;
import com.aventstack.extentreports.utils.FileUtil;
public class HttpMediaManagerImplKlov
@@ -36,10 +37,13 @@ public void init(String host) throws IOException {
@Override
public void storeMedia(Media m) throws IOException {
- if (m.getPath() == null || m.getBase64String() != null)
+ if (m.getPath() == null) {
return;
-
- File f = new File(m.getPath());
+ }
+ if (m instanceof ScreenCapture && ((ScreenCapture)m).getBase64String() != null) {
+ return;
+ }
+ File f = new File(m.getResolvedPath());
if (!f.exists()) {
throw new IOException("The system cannot find the file specified " + m.getPath());
}
@@ -54,14 +58,13 @@ public void storeMedia(Media m) throws IOException {
MultipartEntityBuilder builder = MultipartEntityBuilder.create();
builder.setMode(HttpMultipartMode.BROWSER_COMPATIBLE);
builder.addPart("name",new StringBody(m.getSequence() + "." + ext, ContentType.TEXT_PLAIN));
- builder.addPart("id", new StringBody(m.getObjectId().toString(), ContentType.TEXT_PLAIN));
- builder.addPart("reportId", new StringBody(m.getReportObjectId().toString(), ContentType.TEXT_PLAIN));
- builder.addPart("testId", new StringBody(m.getTestObjectId().toString(), ContentType.TEXT_PLAIN));
- builder.addPart("mediaType", new StringBody(String.valueOf(m.getMediaType()).toLowerCase(), ContentType.TEXT_PLAIN));
- builder.addPart("f", new FileBody(new File(m.getPath())));
+ builder.addPart("id", new StringBody(m.getBsonId().get("id").toString(), ContentType.TEXT_PLAIN));
+ builder.addPart("reportId", new StringBody(m.getBsonId().get("reportId").toString(), ContentType.TEXT_PLAIN));
+ builder.addPart("testId", new StringBody(m.getBsonId().get("testId").toString(), ContentType.TEXT_PLAIN));
+ builder.addPart("f", new FileBody(new File(m.getResolvedPath())));
post.setEntity(builder.build());
- String logId = m.getLogObjectId() == null ? "" : m.getLogObjectId().toString();
+ String logId = m.getBsonId().get("logId") == null ? "" : m.getBsonId().get("logId").toString();
builder.addPart("logId", new StringBody(logId, ContentType.TEXT_PLAIN));
HttpClient client = HttpClientBuilder.create().build();
@@ -76,7 +79,7 @@ public void storeMedia(Media m) throws IOException {
}
private boolean isResponseValid(int responseCode) {
- return 200 <= responseCode && responseCode <= 399;
+ return responseCode >= 200 && responseCode < 400;
}
}
diff --git a/src/main/java/com/aventstack/extentreports/model/AbstractStructure.java b/src/main/java/com/aventstack/extentreports/model/AbstractStructure.java
index 38fd521..356fc13 100644
--- a/src/main/java/com/aventstack/extentreports/model/AbstractStructure.java
+++ b/src/main/java/com/aventstack/extentreports/model/AbstractStructure.java
@@ -11,12 +11,8 @@ public class AbstractStructure implements Serializable {
private static final long serialVersionUID = -2630417398255980331L;
- private transient List list;
+ private List list = Collections.synchronizedList(new ArrayList<>());
- AbstractStructure() {
- list = Collections.synchronizedList(new ArrayList<>());
- }
-
public void add(T t) {
list.add(t);
}
@@ -38,8 +34,9 @@ public List getAll() {
}
public int size() {
- if (list == null)
+ if (list == null) {
return 0;
+ }
return list.size();
}
@@ -76,4 +73,4 @@ public void remove() {
}
}
-}
+}
\ No newline at end of file
diff --git a/src/main/java/com/aventstack/extentreports/model/Attribute.java b/src/main/java/com/aventstack/extentreports/model/Attribute.java
index 2b1e436..77494d7 100644
--- a/src/main/java/com/aventstack/extentreports/model/Attribute.java
+++ b/src/main/java/com/aventstack/extentreports/model/Attribute.java
@@ -2,36 +2,39 @@
import java.io.Serializable;
-abstract class Attribute
- implements Serializable {
-
- private static final long serialVersionUID = 6491172989326625178L;
-
- private String k;
- private String v;
-
- public Attribute(String k, String v) {
- this.k = k;
- this.v = v;
- }
-
- public Attribute(String k) {
- this(k, null);
- }
-
- protected String getKey() {
- return k;
- }
-
- protected void setKey(String k) {
- this.k = k;
- }
-
- public String getValue() {
- return v;
- }
-
- public void setValue(String v) {
- this.v = v;
- }
-}
+public class Attribute implements Serializable {
+
+ private static final long serialVersionUID = 6491172989326625178L;
+
+ private String k;
+ private String v;
+
+ public Attribute() {
+ }
+
+ public Attribute(String k, String v) {
+ this.k = k;
+ this.v = v;
+ }
+
+ public Attribute(String k) {
+ this(k, null);
+ }
+
+ public String getName() {
+ return k;
+ }
+
+ public void setName(String k) {
+ this.k = k;
+ }
+
+ public String getValue() {
+ return v;
+ }
+
+ public void setValue(String v) {
+ this.v = v;
+ }
+
+}
\ No newline at end of file
diff --git a/src/main/java/com/aventstack/extentreports/model/Author.java b/src/main/java/com/aventstack/extentreports/model/Author.java
index 3e26b3a..2e3b6b1 100644
--- a/src/main/java/com/aventstack/extentreports/model/Author.java
+++ b/src/main/java/com/aventstack/extentreports/model/Author.java
@@ -1,12 +1,15 @@
package com.aventstack.extentreports.model;
-public class Author
- extends TestAttribute {
+public class Author extends Attribute {
- private static final long serialVersionUID = 5358337504569462439L;
+ private static final long serialVersionUID = -6374771272610470521L;
- public Author(String k) {
- super(k);
- }
-
-}
+ public Author(String k) {
+ super(k);
+ }
+
+ public Author(String k, String v) {
+ super(k, v);
+ }
+
+}
\ No newline at end of file
diff --git a/src/main/java/com/aventstack/extentreports/model/Category.java b/src/main/java/com/aventstack/extentreports/model/Category.java
index a2195ac..f9eb334 100644
--- a/src/main/java/com/aventstack/extentreports/model/Category.java
+++ b/src/main/java/com/aventstack/extentreports/model/Category.java
@@ -1,12 +1,15 @@
package com.aventstack.extentreports.model;
-public class Category
- extends TestAttribute {
+public class Category extends Attribute {
- private static final long serialVersionUID = -7850780488330456977L;
+ private static final long serialVersionUID = 2652701333761577144L;
- public Category(String k) {
- super(k);
- }
-
-}
+ public Category(String k) {
+ super(k);
+ }
+
+ public Category(String k, String v) {
+ super(k, v);
+ }
+
+}
\ No newline at end of file
diff --git a/src/main/java/com/aventstack/extentreports/model/Device.java b/src/main/java/com/aventstack/extentreports/model/Device.java
index 05a99f5..e148219 100644
--- a/src/main/java/com/aventstack/extentreports/model/Device.java
+++ b/src/main/java/com/aventstack/extentreports/model/Device.java
@@ -1,12 +1,15 @@
package com.aventstack.extentreports.model;
-public class Device
- extends TestAttribute {
+public class Device extends Attribute {
- private static final long serialVersionUID = 4823653818257315805L;
+ private static final long serialVersionUID = -3675996041755598043L;
- public Device(String device) {
- super(device);
+ public Device(String k) {
+ super(k);
+ }
+
+ public Device(String k, String v) {
+ super(k, v);
}
-}
+}
\ No newline at end of file
diff --git a/src/main/java/com/aventstack/extentreports/model/ExceptionInfo.java b/src/main/java/com/aventstack/extentreports/model/ExceptionInfo.java
index ee05a60..bbadc83 100644
--- a/src/main/java/com/aventstack/extentreports/model/ExceptionInfo.java
+++ b/src/main/java/com/aventstack/extentreports/model/ExceptionInfo.java
@@ -2,39 +2,31 @@
import java.io.Serializable;
-import com.aventstack.extentreports.utils.ExceptionUtil;
-
public class ExceptionInfo implements Serializable {
private static final long serialVersionUID = 2672123037706464734L;
private String exceptionName;
private String stackTrace;
- private Throwable t;
-
- public ExceptionInfo() { }
-
- public ExceptionInfo(Throwable t) {
- setException(t);
- setExceptionName(ExceptionUtil.getExceptionHeadline(t));
- setStackTrace(ExceptionUtil.getStackTrace(t));
- }
-
- // exception-name
- public String getExceptionName() { return exceptionName; }
-
- public void setExceptionName(String exceptionName) { this.exceptionName = exceptionName; }
-
- // stack-trace
- public String getStackTrace() { return stackTrace; }
-
- public void setStackTrace(String stackTrace) {
- this.stackTrace = stackTrace;
- }
-
- // exception
- public void setException(Throwable t) { this.t = t; }
-
- public Throwable getException() { return t; }
-
+ private Throwable throwable;
+
+ public String getExceptionName() {
+ return exceptionName;
+ }
+ public void setExceptionName(String exceptionName) {
+ this.exceptionName = exceptionName;
+ }
+ public String getStackTrace() {
+ return stackTrace;
+ }
+ public void setStackTrace(String stackTrace) {
+ this.stackTrace = stackTrace;
+ }
+ public Throwable getThrowable() {
+ return throwable;
+ }
+ public void setThrowable(Throwable throwable) {
+ this.throwable = throwable;
+ }
+
}
\ No newline at end of file
diff --git a/src/main/java/com/aventstack/extentreports/model/ExceptionTestContext.java b/src/main/java/com/aventstack/extentreports/model/ExceptionTestContext.java
deleted file mode 100644
index 1d30a1c..0000000
--- a/src/main/java/com/aventstack/extentreports/model/ExceptionTestContext.java
+++ /dev/null
@@ -1,31 +0,0 @@
-package com.aventstack.extentreports.model;
-
-import java.io.Serializable;
-import java.util.ArrayList;
-import java.util.List;
-
-public class ExceptionTestContext
- implements Serializable {
-
- private static final long serialVersionUID = -2516200535748363722L;
-
- private ExceptionInfo exceptionInfo;
- private List testList = new ArrayList<>();
-
- public ExceptionTestContext(ExceptionInfo exceptionInfo) {
- this.exceptionInfo = exceptionInfo;
- }
-
- public void setTest(Test test) {
- testList.add(test);
- }
-
- public List getTestList() {
- return testList;
- }
-
- public ExceptionInfo getExceptionInfo() {
- return exceptionInfo;
- }
-
-}
diff --git a/src/main/java/com/aventstack/extentreports/model/IAddsMedia.java b/src/main/java/com/aventstack/extentreports/model/IAddsMedia.java
deleted file mode 100644
index 87d95d3..0000000
--- a/src/main/java/com/aventstack/extentreports/model/IAddsMedia.java
+++ /dev/null
@@ -1,59 +0,0 @@
-package com.aventstack.extentreports.model;
-
-import java.io.IOException;
-
-public interface IAddsMedia {
-
- /**
- * Adds a snapshot to the test or log with title
- *
- * @param imagePath Image path
- * @param title Image title
- *
- * @return Object this method is called from, generally {@link com.aventstack.extentreports.ExtentTest} or {@link Log}
- *
- * @throws IOException thrown if the imagePath of image is not found
- */
- T addScreenCaptureFromPath(String imagePath, String title) throws IOException;
-
- /**
- * Adds a snapshot to test or log
- *
- * @param imagePath Image path
- *
- * @return Object this method is called from, generally {@link com.aventstack.extentreports.ExtentTest} or {@link Log}
- *
- * @throws IOException thrown if the imagePath of image is not found
- */
- T addScreenCaptureFromPath(String imagePath) throws IOException;
-
- /**
- * Adds a base64 screenshot
- *
- * @param s base64 string
- * @param title Image title
- *
- * @return Object this method is called from, generally {@link com.aventstack.extentreports.ExtentTest} or {@link Log}
- */
- T addScreenCaptureFromBase64String(String s, String title);
-
- /**
- * Adds a base64 screenshot
- *
- * @param s base64 string
- *
- * @return Object this method is called from, generally {@link com.aventstack.extentreports.ExtentTest} or {@link Log}
- */
- T addScreenCaptureFromBase64String(String s);
-
- /**
- * Adds a screencast to test or log
- *
- * @param screencastPath Screencast path
- *
- * @return Object this method is called from, generally {@link com.aventstack.extentreports.ExtentTest} or {@link Log}
- *
- * @throws IOException thrown if the screencastPath of image is not found
- */
- T addScreencastFromPath(String screencastPath) throws IOException;
-}
diff --git a/src/main/java/com/aventstack/extentreports/model/Log.java b/src/main/java/com/aventstack/extentreports/model/Log.java
index 204d2d0..3532094 100644
--- a/src/main/java/com/aventstack/extentreports/model/Log.java
+++ b/src/main/java/com/aventstack/extentreports/model/Log.java
@@ -6,147 +6,93 @@
import org.bson.types.ObjectId;
-import com.aventstack.extentreports.ExtentTest;
import com.aventstack.extentreports.RunResult;
import com.aventstack.extentreports.Status;
-import com.aventstack.extentreports.markuputils.Markup;
-
-public class Log
- implements RunResult, Serializable, BasicMongoReportElement {
-
- private static final long serialVersionUID = 1594512136869286425L;
-
- private AbstractStructure screenCaptureContext;
- private AbstractStructure screencastContext;
- private ExtentTest parent;
- private Test parentModel;
- private Markup markup;
- private Date timestamp = Calendar.getInstance().getTime();
- private Status logStatus;
- private String stepName;
- private String details;
- private int sequence;
- private ObjectId objectId;
- private ExceptionInfo exceptionInfo;
-
- public Log(Test test) {
- this.parentModel = test;
- }
-
- public Log(ExtentTest test) {
- this.parent = test;
- }
-
- public Date getTimestamp() {
- return timestamp;
- }
- public void setTimestamp(Date timestamp) {
- this.timestamp = timestamp;
- }
-
- public void setStatus(Status logStatus) {
- this.logStatus = logStatus;
- }
- public Status getStatus() {
- return logStatus;
- }
-
- public void setStepName(String stepName) {
- this.stepName = stepName;
- }
- public String getStepName() {
- return stepName;
- }
-
- public void setDetails(String details) {
- this.details = details;
- }
- public String getDetails() {
- return details;
- }
-
- public void setMarkup(Markup markup) {
- this.markup = markup;
- }
- public Markup getMarkup() {
- return markup;
- }
-
- public void setSequence(int sequence) {
- this.sequence = sequence;
- }
- public int getSequence() {
- return sequence;
- }
-
- public void setScreenCapture(ScreenCapture screenCapture) {
- if (screenCaptureContext == null) {
- screenCaptureContext = new AbstractStructure<>();
- }
- screenCaptureContext.add(screenCapture);
- screenCapture.setTestObjectId(getParent().getModel().getObjectId());
- }
-
- public AbstractStructure getScreenCaptureContext() {
- return screenCaptureContext;
- }
-
- public boolean hasScreenCapture() {
- return screenCaptureContext != null
- && screenCaptureContext.size() > 0;
- }
-
- public void setScreencast(Screencast screencast) {
- if (screencastContext == null) {
- screencastContext = new AbstractStructure<>();
- }
- screencastContext.add(screencast);
- }
-
- public AbstractStructure getScreencastContext() {
- return screencastContext;
- }
-
- public boolean hasScreencast() {
- return screencastContext != null
- && screencastContext.size() > 0;
- }
-
- public ExtentTest getParent() {
- return parent;
- }
-
- public Test getParentModel() {
- return parent == null
- ? parentModel
- : parent.getModel();
- }
-
- @Override
- public ObjectId getObjectId() {
- return objectId;
- }
-
- @Override
- public void setObjectId(ObjectId id) {
- objectId = id;
- }
-
- public void setExceptionInfo(ExceptionInfo exceptionInfo) {
- this.exceptionInfo = exceptionInfo;
- }
-
- public ExceptionInfo getExceptionInfo() {
- return exceptionInfo;
- }
-
- @Override
- public String toString() {
- return "[log] " +
- " {timestamp: " + getTimestamp() + "," +
- " status: " + getStatus() + "," +
- " details: " + getDetails() +
- " }";
- }
-
-}
\ No newline at end of file
+
+public class Log implements Serializable, RunResult, BasicMongoReportElement {
+
+ private static final long serialVersionUID = 8072065800800347981L;
+ private Date timestamp = Calendar.getInstance().getTime();
+
+ private ExceptionInfo exceptionInfo;
+ private AbstractStructure screenCaptureContext;
+ private transient Test test;
+ private Status status;
+ private String details;
+ private int sequence;
+ private ObjectId objectId;
+
+ public Log(Test test) {
+ this.test = test;
+ }
+
+ public Date getTimestamp() {
+ return timestamp;
+ }
+
+ public void setTimestamp(Date timestamp) {
+ this.timestamp = timestamp;
+ }
+
+ public ExceptionInfo getExceptionInfo() {
+ return exceptionInfo;
+ }
+
+ public void setExceptionInfo(ExceptionInfo exceptionInfo) {
+ this.exceptionInfo = exceptionInfo;
+ }
+
+ public AbstractStructure getScreenCaptureContext() {
+ if (screenCaptureContext == null) {
+ screenCaptureContext = new AbstractStructure<>();
+ }
+ return screenCaptureContext;
+ }
+
+ public void setScreenCaptureContext(AbstractStructure screenCapture) {
+ this.screenCaptureContext = screenCapture;
+ }
+
+ public Test getTest() {
+ return test;
+ }
+
+ public void setTest(Test test) {
+ this.test = test;
+ }
+
+ public Status getStatus() {
+ return status;
+ }
+
+ public void setStatus(Status status) {
+ this.status = status;
+ }
+
+ public String getDetails() {
+ return details;
+ }
+
+ public void setDetails(String details) {
+ this.details = details;
+ }
+
+ public int getSequence() {
+ return sequence;
+ }
+
+ public void setSequence(int sequence) {
+ this.sequence = sequence;
+ }
+
+ @Override
+ public ObjectId getObjectId() {
+ return objectId;
+ }
+
+ @Override
+ public void setObjectId(ObjectId id) {
+ this.objectId = id;
+ }
+
+}
diff --git a/src/main/java/com/aventstack/extentreports/model/Media.java b/src/main/java/com/aventstack/extentreports/model/Media.java
index f87ea9e..b5343c5 100644
--- a/src/main/java/com/aventstack/extentreports/model/Media.java
+++ b/src/main/java/com/aventstack/extentreports/model/Media.java
@@ -1,119 +1,79 @@
package com.aventstack.extentreports.model;
import java.io.Serializable;
+import java.util.HashMap;
+import java.util.Map;
import org.bson.types.ObjectId;
-import com.aventstack.extentreports.utils.FileUtil;
-
-public class Media
- implements Serializable {
-
- private static final long serialVersionUID = -5706630485211806728L;
-
- private ObjectId id;
- private ObjectId reportId;
- private ObjectId testId;
- private ObjectId logId;
- private String name;
- private String description;
- private String path;
- private String base64String;
- private int seq;
- private long fileSize = 0;
-
- private MediaType mediaType;
-
- public void setObjectId(ObjectId id) {
- this.id = id;
- }
-
- public ObjectId getObjectId() {
- return id;
+public class Media implements Serializable {
+
+ private static final long serialVersionUID = 2620739620884939951L;
+ private String name = "";
+ private String description;
+ private String path;
+ private int sequence;
+ private long fileSize = 0;
+ private Map bsonId;
+ private String resolvedPath;
+
+ public String getName() {
+ return name;
}
-
- public void setReportObjectId(ObjectId reportId) {
- this.reportId = reportId;
- }
-
- public ObjectId getReportObjectId() {
- return reportId;
+
+ public void setName(String name) {
+ this.name = name;
}
- public void setTestObjectId(ObjectId testId) {
- this.testId = testId;
- }
-
- public ObjectId getTestObjectId() {
- return testId;
+ public String getDescription() {
+ return description;
}
-
- public void setLogObjectId(ObjectId logId) {
- this.logId = logId;
- }
-
- public ObjectId getLogObjectId() {
- return logId;
+
+ public void setDescription(String description) {
+ this.description = description;
}
-
- public void setName(String name) {
- this.name = name;
- }
-
- public String getName() {
- return name;
+
+ public String getPath() {
+ return path;
}
-
- protected void setDescription(String description) {
- this.description = description;
- }
-
- protected String getDescription() {
- return description;
+
+ public void setPath(String path) {
+ this.path = path;
}
-
- public void setPath(String path) {
- this.path = path;
- setFileSize(FileUtil.getFileSize(path));
- if (getName() == null || getName().isEmpty())
- setName(FileUtil.getFileName(path));
- }
-
- public String getPath() {
- return path;
+
+ public int getSequence() {
+ return sequence;
}
- public long getFileSize() {
- return fileSize;
- }
+ public void setSequence(int sequence) {
+ this.sequence = sequence;
+ }
- public void setFileSize(long fileSize) {
- this.fileSize = fileSize;
- }
+ public long getFileSize() {
+ return fileSize;
+ }
+
+ public void setFileSize(long fileSize) {
+ this.fileSize = fileSize;
+ }
+
+ public Map getBsonId() {
+ if (bsonId == null) {
+ bsonId = new HashMap<>();
+ }
+ return bsonId;
+ }
+
+ public void setBsonId(Map bsonId) {
+ this.bsonId = bsonId;
+ }
- public void setMediaType(MediaType mediaType) {
- this.mediaType = mediaType;
- }
-
- public MediaType getMediaType() {
- return mediaType;
+ public String getResolvedPath() {
+ return resolvedPath == null ? getPath() : resolvedPath;
}
- public void setSequence(int seq) {
- this.seq = seq;
- }
-
- public int getSequence() {
- return seq;
+ public void setResolvedPath(String resolvedPath) {
+ this.resolvedPath = resolvedPath;
}
- public void setBase64String(String string) {
- string = string.contains("data:") || string.contains("image/") ? string : "data:image/png;base64," + string;
- this.base64String = string;
- }
-
- public String getBase64String() {
- return base64String;
- }
-
}
diff --git a/src/main/java/com/aventstack/extentreports/model/MediaType.java b/src/main/java/com/aventstack/extentreports/model/MediaType.java
deleted file mode 100644
index 6163475..0000000
--- a/src/main/java/com/aventstack/extentreports/model/MediaType.java
+++ /dev/null
@@ -1,6 +0,0 @@
-package com.aventstack.extentreports.model;
-
-public enum MediaType {
- IMG,
- VID
-}
diff --git a/src/main/java/com/aventstack/extentreports/model/ScreenCapture.java b/src/main/java/com/aventstack/extentreports/model/ScreenCapture.java
index 1021c4a..493d296 100644
--- a/src/main/java/com/aventstack/extentreports/model/ScreenCapture.java
+++ b/src/main/java/com/aventstack/extentreports/model/ScreenCapture.java
@@ -1,26 +1,31 @@
package com.aventstack.extentreports.model;
-public class ScreenCapture
- extends Media {
+public class ScreenCapture extends Media {
- private static final long serialVersionUID = -3413285738443448335L;
+ private static final long serialVersionUID = 3876935785138278521L;
+ private String base64;
- public String getSource() {
- if (getBase64String() != null)
- return "base64-img";
+ public String getBase64String() {
+ return base64;
+ }
- return "";
- }
-
- public String getSourceWithIcon() {
- return "img";
- }
-
- public String getScreenCapturePath() {
- return getPath() != null ? getPath() : getBase64String();
- }
+ public void setBase64String(String base64) {
+ base64 = base64.contains("data:") || base64.contains("image/") ? base64 : "data:image/png;base64," + base64;
+ this.base64 = base64;
+ }
+
+ public String getScreenCapturePath() {
+ return getPath() != null ? getPath() : getBase64String();
+ }
- public Boolean isBase64() {
- return getBase64String() != null;
+ public Boolean isBase64() {
+ return getBase64String() != null;
+ }
+
+ public String getSource() {
+ if (getBase64String() != null)
+ return "base64-img";
+ return "";
}
-}
\ No newline at end of file
+
+}
diff --git a/src/main/java/com/aventstack/extentreports/model/Screencast.java b/src/main/java/com/aventstack/extentreports/model/Screencast.java
deleted file mode 100644
index e3c3c81..0000000
--- a/src/main/java/com/aventstack/extentreports/model/Screencast.java
+++ /dev/null
@@ -1,19 +0,0 @@
-package com.aventstack.extentreports.model;
-
-public class Screencast
- extends Media {
-
- private static final long serialVersionUID = -3413285738443448335L;
-
- public String getSource() {
- return "";
- }
-
- public String getSourceWithIcon() {
- return getSource();
- }
-
-}
diff --git a/src/main/java/com/aventstack/extentreports/model/SystemAttribute.java b/src/main/java/com/aventstack/extentreports/model/SystemAttribute.java
index 13baa26..27ed149 100644
--- a/src/main/java/com/aventstack/extentreports/model/SystemAttribute.java
+++ b/src/main/java/com/aventstack/extentreports/model/SystemAttribute.java
@@ -1,20 +1,15 @@
package com.aventstack.extentreports.model;
-public class SystemAttribute
- extends Attribute {
+public class SystemAttribute extends Attribute {
- private static final long serialVersionUID = 7531709191041382750L;
+ private static final long serialVersionUID = -6374771272610470521L;
- public SystemAttribute(String k, String v) {
- super(k, v);
- }
-
- public String getName() {
- return getKey();
- }
-
- public void setName(String name) {
- setKey(name);
- }
+ public SystemAttribute(String k) {
+ super(k);
+ }
-}
+ public SystemAttribute(String k, String v) {
+ super(k, v);
+ }
+
+}
\ No newline at end of file
diff --git a/src/main/java/com/aventstack/extentreports/model/Test.java b/src/main/java/com/aventstack/extentreports/model/Test.java
index 9ae3719..0df24fb 100644
--- a/src/main/java/com/aventstack/extentreports/model/Test.java
+++ b/src/main/java/com/aventstack/extentreports/model/Test.java
@@ -1,12 +1,9 @@
package com.aventstack.extentreports.model;
import java.io.Serializable;
-import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
-import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
-import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
import org.bson.types.ObjectId;
@@ -15,505 +12,373 @@
import com.aventstack.extentreports.RunResult;
import com.aventstack.extentreports.Status;
import com.aventstack.extentreports.gherkin.model.IGherkinFormatterModel;
+import com.google.gson.annotations.Expose;
-public class Test
- implements BasicMongoReportElement, RunResult, Serializable {
+public class Test implements Serializable, RunResult, BasicMongoReportElement {
- private static final long serialVersionUID = 5590943223572254960L;
- private static final AtomicInteger atomicInt = new AtomicInteger(0);
-
- /**
- * An instance of {@link ExtentReports}
- */
- private transient ExtentReports extent;
-
- /**
- * Level describes the hierarchy of the test in the tree. A level 0 indicates a parent
- * test. Level 1 indicates an immediate child of the parent, level 2 indicates an immediate
- * child of the Child and so on.. The bottom-most test in the hierarchy is considered
- * a leaf
- */
- private int level = 0;
-
- /**
- * A unique ID, generated by AtomicInteger
- */
- private int testId = atomicInt.incrementAndGet();
-
- /**
- * If this Test is at the top-most level, or in other words, has a level value of 0, parent
- * will be null. This field will only contain a value if the Test is a child, or has a level
- * 1 or greater.
- */
- private Test parent;
-
- /**
- * {@link Status} of this test, defaults to PASS
- */
- private Status status = Status.PASS;
-
- /**
- * A structure containing all nodes of this test
- */
- private AbstractStructure node;
-
- /**
- * A structure containing all logs/events of this test
- */
- private AbstractStructure log;
-
- /**
- * A structure containing all categories assigned to this test
- */
- private AbstractStructure category;
+ private static final long serialVersionUID = -8681630689550647312L;
+ private static final AtomicInteger atomicInt = new AtomicInteger(0);
- /**
- * A structure containing all authors assigned to this test
- */
- private AbstractStructure author;
-
- /**
- * A structure containing all devices assigned to this test
- */
- private AbstractStructure device;
-
- /**
- * Time the test was started
- */
- private Date startTime = Calendar.getInstance().getTime();
-
- /**
- * Time the test was ended
- */
- private Date endTime = Calendar.getInstance().getTime();
-
- /**
+ /**
+ * An instance of {@link ExtentReports}
+ */
+ private transient ExtentReports extent;
+
+ /**
+ * Level describes the hierarchy of the test in the tree. A level 0 indicates a
+ * parent test. Level 1 indicates an immediate child of the parent, level 2
+ * indicates an immediate child of the Child and so on.. The bottom-most test in
+ * the hierarchy is considered a leaf
+ */
+ private int level = 0;
+
+ /**
+ * A unique ID, generated by AtomicInteger
+ */
+ private transient int id = atomicInt.incrementAndGet();
+
+ /**
* An assigned {@link ObjectId}
*/
- private ObjectId mongoId;
-
- /**
- * Type of BDD object represented by {@link IGherkinFormatterModel}. It can have one
- * of the following values:
- *
- *
- */
- private Class extends IGherkinFormatterModel> bddType;
-
- /**
- * A list of {@link ScreenCapture}
- */
- private transient List screenCaptureList;
-
- /**
- * A list of {@link Screencast}
- */
- private transient List screencastList;
-
- /**
- * A list of {@link ExceptionInfo}
- */
- private transient List exceptionList;
-
- /**
- * Name of the test
- */
- private String name;
-
- /**
- * Hierarchical name of the test
- *
- *
- * Note: This field will equal the name if the test is the top-most level.
- *
- *
- * For tests having level 1 or greater, the hierarchical name would be separated by
- * a dot character as:
- *
- * Test.Child.GrandChild
- */
- private String hierarchicalName;
-
- /**
- * Description
- */
- private String description;
-
- /**
- * Indicates if the test has ended
- */
- private boolean ended = false;
-
- /**
- * This setting allows setting test with your own time-stamps. With this enabled, Extent
- * does not use time-stamps for tests at the time they were created
- */
- private boolean usesManualConfiguration = false;
-
-
- // if used via listener, allow manual configuration of model
- public void setUseManualConfiguration(boolean b) {
- this.usesManualConfiguration = b;
- }
-
- public ExtentReports getExtentInstance() {
- return extent;
- }
-
- public void setExtentInstance(ExtentReports extent) {
- this.extent = extent;
- }
-
- public boolean isChildNode() {
- return level > 0;
- }
-
- public int getLevel() {
- return level;
- }
-
- public void setLevel(int level) {
- this.level = level;
- }
-
-
- public void setParent(Test parent) {
- this.parent = parent;
- }
-
- public Test getParent() { return parent; }
-
- public AbstractStructure getNodeContext() {
- if (node == null) {
- node = new AbstractStructure<>();
- }
-
- return node;
- }
-
- public boolean hasChildren() {
- return node != null && node.getAll() != null && node.getAll().size() > 0;
- }
-
- public void setStartTime(Date startTime) {
- this.startTime = startTime;
- }
-
- public Date getStartTime() {
- return startTime;
- }
-
- public void setEndTime(Date endTime) {
- this.endTime = endTime;
- }
-
- private void setEndTimeFromChildren() {
- if (hasChildren()) {
- setStartTime(getNodeContext().getFirst().getStartTime());
- setEndTime(getNodeContext().getLast().getEndTime());
- } else if (hasLog()) {
- Date lastLogEndTime = getLogContext().getLast().getTimestamp();
- setEndTime(lastLogEndTime);
- }
- }
-
- public Date getEndTime() {
- return endTime;
- }
-
- public boolean hasEnded() {
- return ended;
- }
-
- public String getRunDuration() {
- long diff = endTime.getTime() - startTime.getTime();
-
- long secs = diff / 1000;
- long millis = diff % 1000;
- long mins = secs / 60;
- secs = secs % 60;
- long hours = mins / 60;
- mins = mins % 60;
-
- return hours + "h " + mins + "m " + secs + "s+" + millis + "ms";
- }
-
- public Long getRunDurationMillis() {
- return endTime.getTime() - startTime.getTime();
- }
-
- // default status when the test starts
- public void setStatus(Status status) {
- this.status = status;
- }
-
- public Status getStatus() {
- return status;
- }
-
- public void trackLastRunStatus() {
- getLogContext().getAll().forEach(x -> updateStatus(x.getStatus()));
-
- status = (status == Status.INFO || status == Status.DEBUG)
- ? Status.PASS
- : status;
- }
-
- private synchronized void updateStatus(Status logStatus) {
- int logStatusIndex = Status.getStatusHierarchy().indexOf(logStatus);
- int testStatusIndex = Status.getStatusHierarchy().indexOf(status);
-
- status = logStatusIndex < testStatusIndex ? logStatus : status;
- }
-
- public void end() {
- updateTestStatusRecursive(this);
- endChildrenRecursive(this);
-
- status = (status == Status.INFO || status == Status.DEBUG)
- ? Status.PASS
- : status;
-
- if (!usesManualConfiguration)
- setEndTimeFromChildren();
- }
-
- private synchronized void updateTestStatusRecursive(Test test) {
- test.getLogContext().getAll().forEach(x -> updateStatus(x.getStatus()));
-
- if (test.hasChildren()) {
- test.getNodeContext().getAll().forEach(this::updateTestStatusRecursive);
- }
-
- // if not all children are marked SKIP, then:
- // ensure the parent has a status that is not SKIP
- if (!test.isBehaviorDrivenType()) {
- boolean hasNodeNotSkipped = test.getNodeContext().getAll()
- .stream()
- .anyMatch(x -> x.getStatus() != Status.SKIP);
-
- if (status == Status.SKIP && hasNodeNotSkipped) {
- // reset status
- status = Status.PASS;
- // compute new status
- test.getNodeContext().getAll()
- .stream()
- .filter(x -> x.getStatus() != Status.SKIP)
- .forEach(this::updateTestStatusRecursive);
- }
- }
- }
-
- private void endChildrenRecursive(Test test) {
- test.getNodeContext().getAll().forEach(Test::end);
- }
-
- public AbstractStructure getLogContext() {
- if (log == null) {
- log = new AbstractStructure<>();
- }
- return log;
- }
-
- public boolean hasLog() {
- return log != null && !log.isEmpty();
- }
-
- public void setDescription(String description) {
- this.description = description;
- }
-
- public String getDescription() { return description; }
-
- public void setName(String name) {
- this.name = name;
- }
-
- public String getName() {
- return name;
- }
-
- public String getHierarchicalName() {
- hierarchicalName = parent == null
- ? name
- : String.join(".", parent.getHierarchicalName(), getName());
- return hierarchicalName;
- }
-
- public boolean hasAttributes() {
- return hasAuthor() || hasCategory() || hasDevice();
- }
-
- public AbstractStructure getCategoryContext() {
- if (category == null) {
- category = new AbstractStructure<>();
- }
- return category;
- }
-
- public boolean hasCategory(String name) {
- return hasCategory()
- && category.getAll()
- .stream()
- .anyMatch(x -> x.getName().equals(name));
- }
-
- public boolean hasCategoryNode(String name) {
- return getNodeContext().getAll()
- .stream()
- .anyMatch(x -> x.hasCategory(name));
- }
-
- public boolean hasCategory() {
- return category != null && !category.isEmpty();
- }
-
- public void setCategory(TestAttribute category) {
- getCategoryContext().add(category);
- }
-
- public TestAttribute getCategory(Integer index) {
- if (hasCategory() && index < category.size()) {
- return category.get(index);
- }
- return null;
- }
-
- public AbstractStructure getAuthorContext() {
- if (author == null) {
- author = new AbstractStructure<>();
- }
- return author;
- }
-
- public boolean hasAuthor() {
- return author != null && !author.isEmpty();
- }
-
- public void setAuthor(TestAttribute author) {
- getAuthorContext().add(author);
- }
-
- public TestAttribute getAuthor(Integer index) {
- if (hasAuthor() && index < author.size()) {
- return author.get(index);
- }
- return null;
- }
-
- public AbstractStructure getDeviceContext() {
- if (device == null) {
- device = new AbstractStructure<>();
- }
- return device;
- }
-
- public boolean hasDevice() {
- return device != null && !device.isEmpty();
- }
-
- public void setDevice(TestAttribute device) {
- getDeviceContext().add(device);
- }
-
- public TestAttribute getDevice(Integer index) {
- if (hasDevice() && index < author.size()) {
- return device.get(index);
- }
- return null;
- }
-
- public void setExceptionInfo(ExceptionInfo exceptionInfo) {
- if (exceptionList == null) {
- exceptionList = new ArrayList<>();
- }
- exceptionList.add(exceptionInfo);
- }
-
- public List getExceptionInfoList() {
- return exceptionList;
- }
-
- public boolean hasException() {
- return exceptionList != null && !exceptionList.isEmpty();
- }
-
- public boolean hasMedia() {
- return screenCaptureList != null
- && !screenCaptureList.isEmpty()
- && screencastList != null
- && !screencastList.isEmpty();
- }
-
- public void setScreenCapture(ScreenCapture screenCapture) {
- if (screenCaptureList == null) {
- screenCaptureList = new ArrayList<>();
- }
- screenCaptureList.add(screenCapture);
- }
-
- public List getScreenCaptureList() {
- return screenCaptureList;
- }
-
- public Boolean hasScreenCapture() {
- return screenCaptureList != null && !screenCaptureList.isEmpty();
- }
-
- public void setScreencast(Screencast screencast) {
- if (screencastList == null) {
- screencastList = new ArrayList<>();
- }
- screencastList.add(screencast);
- }
-
- public List getScreencastList() {
- return screencastList;
- }
-
- public boolean isBehaviorDrivenType() {
- return bddType != null;
- }
-
- public void setBehaviorDrivenType(IGherkinFormatterModel type) {
- bddType = type.getClass();
- }
-
- public void setBehaviorDrivenType(Class extends IGherkinFormatterModel> type) {
- bddType = type;
- }
-
- public Class extends IGherkinFormatterModel> getBehaviorDrivenType() {
- return bddType;
- }
-
- public String getBehaviorDrivenTypeName() throws NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
- Method method = bddType.getMethod("getGherkinName");
- Object o = method.invoke(null, (Object[]) null);
- return o.toString();
- }
-
- void setID(int id) {
- testId = id;
- }
-
- public int getID() {
- return testId;
- }
-
- public void setObjectId(ObjectId id) {
- mongoId = id;
- }
-
- public ObjectId getObjectId() {
- return mongoId;
+ private ObjectId objectId;
+
+ /**
+ * If this Test is at the top-most level, or in other words, has a level value
+ * of 0, parent will be null. This field will only contain a value if the Test
+ * is a child, or has a level 1 or greater.
+ */
+ private transient Test parent;
+
+ /**
+ * {@link Status} of this test, defaults to PASS
+ */
+ private Status status = Status.PASS;
+
+ /**
+ * A structure containing all nodes of this test
+ */
+ private AbstractStructure nodeContext;
+
+ /**
+ * A structure containing all logs/events of this test
+ */
+ private AbstractStructure logContext;
+
+ /**
+ * A structure containing all categories assigned to this test
+ */
+ private AbstractStructure categoryContext;
+
+ /**
+ * A structure containing all authors assigned to this test
+ */
+ private AbstractStructure authorContext;
+
+ /**
+ * A structure containing all devices assigned to this test
+ */
+ private AbstractStructure deviceContext;
+
+ /**
+ * Time the test was started
+ */
+ private Date startTime = Calendar.getInstance().getTime();
+
+ /**
+ * Time the test was ended
+ */
+ private Date endTime = Calendar.getInstance().getTime();
+
+ /**
+ * Type of BDD object represented by {@link IGherkinFormatterModel}. It can have
+ * one of the following values:
+ *
+ *