Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix 2725 #2759

Merged
merged 2 commits into from May 15, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGES.txt
@@ -1,6 +1,7 @@
Current
7.6.0
Fixed: GITHUB-2741: Show fully qualified name of the test instead of just the function name for better readability of test output.(Krishnan Mahadevan)
Fixed: GITHUB-2725: Honour custom attribute values in TestNG default reports (Krishnan Mahadevan)
Fixed: GITHUB-2726: @AfterClass config method is executed for EACH @Test method when parallel == methods (Krishnan Mahadevan)
Fixed: GITHUB-2752: TestListener is being lost when implenting both IClassListener and ITestListener (Krishnan Mahadevan)
New: GITHUB-2724: DataProvider: possibility to unload dataprovider class, when done with it (Dzmitry Sankouski)
Expand Down
Expand Up @@ -26,6 +26,11 @@ public class XMLReporterConfig implements IReporterConfig {
public static final String TAG_ATTRIBUTES = "attributes";
public static final String TAG_ATTRIBUTE = "attribute";

public static final String TAG_CUSTOM_ATTRIBUTES = "custom-attributes";
public static final String TAG_CUSTOM_ATTRIBUTE = "custom-attribute";
public static final String TAG_CUSTOM_ATTRIBUTE_NAME = "name";
public static final String TAG_CUSTOM_ATTRIBUTE_VALUE = "value";

public static final String ATTR_URL = "url";
public static final String ATTR_NAME = "name";
public static final String ATTR_STATUS = "status";
Expand Down
4 changes: 2 additions & 2 deletions testng-core/src/main/java/org/testng/JarFileUtils.java
Expand Up @@ -4,6 +4,7 @@
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.util.Collection;
import java.util.Enumeration;
import java.util.List;
Expand All @@ -12,7 +13,6 @@
import java.util.jar.JarFile;
import org.testng.collections.Lists;
import org.testng.internal.Utils;
import org.testng.reporters.Files;
import org.testng.util.Strings;
import org.testng.xml.IPostProcessor;
import org.testng.xml.XmlSuite;
Expand Down Expand Up @@ -76,7 +76,7 @@ private boolean testngXmlExistsInJar(File jarFile, List<String> classes) throws
if (Parser.canParse(jeName.toLowerCase())) {
InputStream inputStream = jf.getInputStream(je);
File copyFile = new File(file, jeName);
Files.copyFile(inputStream, copyFile);
Files.copy(inputStream, copyFile.toPath());
if (matchesXmlPathInJar(je)) {
suitePath = copyFile.toString();
}
Expand Down
Expand Up @@ -12,12 +12,14 @@
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import org.testng.IClass;
import org.testng.IRetryAnalyzer;
import org.testng.ITestClass;
import org.testng.ITestNGMethod;
import org.testng.ITestObjectFactory;
import org.testng.ITestResult;
import org.testng.annotations.CustomAttribute;
import org.testng.annotations.ITestOrConfiguration;
import org.testng.collections.Lists;
import org.testng.collections.Maps;
Expand Down Expand Up @@ -466,11 +468,29 @@ private String computeSignature() {
.append(", instance:")
.append(getInstance())
.append(instanceParameters())
.append(customAttributes())
.append("]");

return result.toString();
}

private String customAttributes() {
CustomAttribute[] attributes = getAttributes();
if (attributes == null || attributes.length == 0) {
return "";
}
return ", attributes: "
+ Arrays.stream(this.getAttributes())
.map(
attribute ->
"<name: "
+ attribute.name()
+ ", value:"
+ Arrays.toString(attribute.values())
+ ">")
.collect(Collectors.joining(", "));
}

public String getSimpleName() {
return m_method.getDeclaringClass().getSimpleName() + "." + m_method.getName();
}
Expand Down
Expand Up @@ -24,6 +24,7 @@
import org.testng.ITestNGMethod;
import org.testng.ITestResult;
import org.testng.Reporter;
import org.testng.annotations.CustomAttribute;
import org.testng.collections.Lists;
import org.testng.internal.Utils;
import org.testng.log4testng.Logger;
Expand Down Expand Up @@ -288,6 +289,22 @@ private void generateForResult(ITestResult ans) {
}
m_out.println("</tr>");
}
CustomAttribute[] attributes = ans.getMethod().getAttributes();
boolean hasCustomAttributes = attributes != null && attributes.length != 0;
if (hasCustomAttributes) {
tableStart("result", null);
m_out.print("<tr class=\"param\">");
for (int x = 1; x <= attributes.length; x++) {
m_out.print("<th>Attribute #" + x + "</th>");
}
m_out.println("</tr>");
m_out.print("<tr class=\"param stripe\">");
for (CustomAttribute p : attributes) {
String text = String.format("name=%s, value= %s", p.name(), Arrays.toString(p.values()));
m_out.println("<td>" + Utils.escapeHtml(text) + "</td>");
}
m_out.println("</tr>");
}
List<String> msgs = Reporter.getOutput(ans);
boolean hasReporterOutput = !msgs.isEmpty();
Throwable exception = ans.getThrowable();
Expand Down
Expand Up @@ -7,6 +7,7 @@
import java.io.IOException;
import java.io.PrintWriter;
import java.text.NumberFormat;
import java.util.Arrays;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;
Expand All @@ -19,6 +20,7 @@
import org.testng.ITestContext;
import org.testng.ITestResult;
import org.testng.Reporter;
import org.testng.annotations.CustomAttribute;
import org.testng.collections.Lists;
import org.testng.internal.Utils;
import org.testng.log4testng.Logger;
Expand Down Expand Up @@ -445,15 +447,12 @@ private void writeScenario(int scenarioIndex, String label, ITestResult result)

writer.print("<table class=\"result\">");

boolean hasRows = false;

// Write test parameters (if any)
Object[] parameters = result.getParameters();
boolean hasRows = dumpParametersInfo("Factory Parameter", result.getFactoryParameters());
int parameterCount = (parameters == null ? 0 : parameters.length);
hasRows = dumpParametersInfo("Factory Parameter", result.getFactoryParameters());
parameters = result.getParameters();
parameterCount = (parameters == null ? 0 : parameters.length);
hasRows = dumpParametersInfo("Parameter", result.getParameters());
dumpAttributesInfo("Attribute(s)", result.getMethod().getAttributes());

// Write reporter messages (if any)
List<String> reporterMessages = Reporter.getOutput(result);
Expand Down Expand Up @@ -529,6 +528,27 @@ private boolean dumpParametersInfo(String prefix, Object[] parameters) {
return true;
}

private void dumpAttributesInfo(String prefix, CustomAttribute[] attributes) {
int parameterCount = (attributes == null ? 0 : attributes.length);
if (parameterCount == 0) {
return;
}
writer.print("<tr class=\"param\">");
writer.print(String.format("<th colspan=3>%s</th>", prefix));
writer.print("</tr>");
writer.print("<tr class=\"param stripe\">");
writer.print("<th>#</th><th>Name</th><th>Value(s)</th>");
writer.print("</tr>");
int i = 1;
for (CustomAttribute attribute : attributes) {
writer.print("<tr>");
writer.print("<td>" + String.format("%02d.", (i++)) + "</td>");
writer.print("<td>" + attribute.name() + "</td>");
writer.print("<td>" + Utils.escapeHtml(Arrays.toString(attribute.values())) + "</td>");
writer.print("</tr>");
}
}

protected void writeReporterMessages(List<String> reporterMessages) {
writer.print("<div class=\"messages\">");
Iterator<String> iterator = reporterMessages.iterator();
Expand Down
26 changes: 17 additions & 9 deletions testng-core/src/main/java/org/testng/reporters/Files.java
Expand Up @@ -14,26 +14,30 @@
import java.io.StringWriter;
import java.io.Writer;
import java.nio.charset.StandardCharsets;
import java.util.stream.Collectors;

public class Files {
public final class Files {

private Files() {
// defeat instantiation
}

/** @deprecated - This method stands deprecated as of TestNG <code>7.6.0</code> */
@Deprecated
public static String readFile(File f) throws IOException {
try (InputStream is = new FileInputStream(f)) {
return readFile(is);
}
}

public static String readFile(InputStream is) throws IOException {
StringBuilder result = new StringBuilder();
BufferedReader br = new BufferedReader(new InputStreamReader(is));
String line = br.readLine();
while (line != null) {
result.append(line).append("\n");
line = br.readLine();
}
return result.toString();
return new BufferedReader(new InputStreamReader(is, StandardCharsets.UTF_8))
.lines()
.collect(Collectors.joining("\n"));
}

/** @deprecated - This method stands deprecated as of TestNG <code>7.6.0</code> */
@Deprecated
public static void writeFile(String string, File f) throws IOException {
f.getParentFile().mkdirs();
try (FileWriter fw = new FileWriter(f);
Expand All @@ -42,6 +46,8 @@ public static void writeFile(String string, File f) throws IOException {
}
}

/** @deprecated - This method stands deprecated as of TestNG <code>7.6.0</code> */
@Deprecated
public static void copyFile(InputStream from, File to) throws IOException {
if (!to.getParentFile().exists()) {
to.getParentFile().mkdirs();
Expand All @@ -57,6 +63,8 @@ public static void copyFile(InputStream from, File to) throws IOException {
}
}

/** @deprecated - This method stands deprecated as of TestNG <code>7.6.0</code> */
@Deprecated
public static String streamToString(InputStream is) throws IOException {
if (is != null) {
Writer writer = new StringWriter();
Expand Down
Expand Up @@ -2,6 +2,7 @@

import java.io.IOException;
import java.io.PrintWriter;
import java.util.Arrays;
import java.util.Collection;
import java.util.Comparator;
import java.util.Date;
Expand All @@ -13,6 +14,7 @@
import org.testng.ITestResult;
import org.testng.Reporter;
import org.testng.TestRunner;
import org.testng.annotations.CustomAttribute;
import org.testng.internal.Utils;
import org.testng.log4testng.Logger;

Expand Down Expand Up @@ -67,6 +69,7 @@ public static void generateTable(
.append("</b></td></tr>\n")
.append("<tr>")
.append("<td><b>Test method</b></td>\n")
.append("<td><b>Attribute(s)</b></td>\n")
.append("<td width=\"30%\"><b>Exception</b></td>\n")
.append("<td width=\"10%\"><b>Time (seconds)</b></td>\n")
.append("<td><b>Instance</b></td>\n")
Expand Down Expand Up @@ -129,7 +132,7 @@ public static void generateTable(
//
{
List<String> output = Reporter.getOutput(tr);
if (null != output && output.size() > 0) {
if (!output.isEmpty()) {
pw.append("<br/>");
// Method name
String divId = "Output-" + tr.hashCode();
Expand All @@ -156,6 +159,35 @@ public static void generateTable(

pw.append("</td>\n");

// Custom attributes
CustomAttribute[] attributes = tr.getMethod().getAttributes();
if (attributes != null && attributes.length > 0) {
pw.append("<td>");
String divId = "attributes-" + tr.hashCode();
pw.append("\n<a href=\"#")
.append(divId)
.append("\"")
.append(" onClick='toggleBox(\"")
.append(divId)
.append("\", this, \"Show attributes\", \"Hide attributes\");'>")
.append("Show attributes</a>\n")
.append("\n<a href=\"#")
.append(divId)
.append("\"></a>");
pw.append("<div class='log' id=\"").append(divId).append("\">\n");
Arrays.stream(attributes)
.map(
attribute ->
"name: " + attribute.name() + ", value:" + Arrays.toString(attribute.values()))
.forEach(
line -> {
pw.append(Utils.escapeHtml(line));
pw.append("<br>");
});
pw.append("</div>");
pw.append("</td>");
}

// Exception
tw = tr.getThrowable();
String stackTrace;
Expand Down
Expand Up @@ -3,6 +3,7 @@
import static org.testng.internal.Utils.isStringNotBlank;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.Set;
Expand All @@ -11,6 +12,7 @@
import org.testng.ITestListener;
import org.testng.ITestNGMethod;
import org.testng.ITestResult;
import org.testng.annotations.CustomAttribute;
import org.testng.collections.Lists;
import org.testng.internal.Utils;

Expand Down Expand Up @@ -52,6 +54,7 @@ private void logResults(ITestContext context) {
"FAILED CONFIGURATION",
Utils.detailedMethodName(tr.getMethod()),
tr.getMethod().getDescription(),
tr.getMethod().getAttributes(),
stackTrace,
tr.getParameters(),
tr.getMethod().getParameterTypes());
Expand All @@ -63,6 +66,7 @@ private void logResults(ITestContext context) {
"SKIPPED CONFIGURATION",
Utils.detailedMethodName(tr.getMethod()),
tr.getMethod().getDescription(),
tr.getMethod().getAttributes(),
null,
tr.getParameters(),
tr.getMethod().getParameterTypes());
Expand Down Expand Up @@ -131,6 +135,7 @@ private void logResult(String status, ITestResult tr, String stackTrace) {
status,
tr.getMethod().getQualifiedName(),
tr.getMethod().getDescription(),
tr.getMethod().getAttributes(),
stackTrace,
tr.getParameters(),
tr.getMethod().getParameterTypes());
Expand Down Expand Up @@ -158,6 +163,7 @@ private void logResult(
String status,
String name,
String description,
CustomAttribute[] attributes,
String stackTrace,
Object[] params,
Class<?>[] paramTypes) {
Expand Down Expand Up @@ -195,6 +201,16 @@ private void logResult(
}
msg.append(description);
}
if (attributes != null && attributes.length != 0) {
msg.append("\nTest Attributes: ");
String testAttributes =
Arrays.stream(attributes)
.map(
attribute ->
"<" + attribute.name() + ", " + Arrays.toString(attribute.values()) + ">")
.collect(Collectors.joining(", "));
msg.append(testAttributes).append("\n");
}
if (!Utils.isStringEmpty(stackTrace)) {
msg.append("\n").append(stackTrace);
}
Expand Down