Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -511,7 +511,7 @@
<dependency>
<groupId>org.jsoup</groupId>
<artifactId>jsoup</artifactId>
<version>1.15.3</version>
<version>1.23.1</version>
</dependency>
<dependency>
<groupId>io.searchbox</groupId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

import java.text.MessageFormat;

import static edu.harvard.iq.dataverse.util.MarkupCheckerUtil.htmlEqualTo;
import static jakarta.ws.rs.core.Response.Status.*;
import java.io.File;
import java.io.IOException;
Expand Down Expand Up @@ -408,7 +409,7 @@ private Long createFeaturedItemAndGetId(String dataverseAlias, String apiToken,
private void verifyUpdatedFeaturedItem(Response response, String expectedContent, String expectedImageFileName, int expectedDisplayOrder, String type, String dvObject, String dvObjectDisplayName) {
response.prettyPrint();
response.then().assertThat()
.body("data.content", equalTo(expectedContent))
.body("data.content", htmlEqualTo(expectedContent))
.body("data.imageFileName", equalTo(expectedImageFileName))
.body("data.displayOrder", equalTo(expectedDisplayOrder))
.body("data.type", equalTo(type))
Expand Down
1 change: 1 addition & 0 deletions src/test/java/edu/harvard/iq/dataverse/api/SearchIT.java
Original file line number Diff line number Diff line change
Expand Up @@ -994,6 +994,7 @@ public void testSubtreePermissions() {

// Wait a little while for the index to pick up the datasets, otherwise timing issue with searching for it.
UtilIT.sleepForDatasetIndex(datasetId2.toString(), apiToken);
UtilIT.sleepForDatasetIndex(datasetId.toString(), apiToken);

String identifier = JsonPath.from(datasetAsJson.getBody().asString()).getString("data.identifier");
String identifier2 = JsonPath.from(datasetAsJson2.getBody().asString()).getString("data.identifier");
Expand Down
29 changes: 13 additions & 16 deletions src/test/java/edu/harvard/iq/dataverse/util/MarkupCheckerTest.java
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
package edu.harvard.iq.dataverse.util;

import org.jsoup.Jsoup;

Check warning on line 3 in src/test/java/edu/harvard/iq/dataverse/util/MarkupCheckerTest.java

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Remove this unused import 'org.jsoup.Jsoup'.

See more on https://sonarcloud.io/project/issues?id=IQSS_dataverse&issues=AaAgyu8wXiAtjKPwcETS&open=AaAgyu8wXiAtjKPwcETS&pullRequest=12596
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.CsvSource;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;

public class MarkupCheckerTest {

Expand All @@ -28,7 +30,12 @@
"NULL, NULL"
}, nullValues = {"NULL"})
public void testSanitizeBasicHTML(String unsafe, String safe) {
assertEquals(safe, MarkupChecker.sanitizeBasicHTML(unsafe));
String actual = MarkupChecker.sanitizeBasicHTML(unsafe);
MarkupCheckerUtil.assertHtmlEqual(safe, actual);
// Sanity check that the key tag we strip is truly gone
if(actual != null) {
assertFalse(actual.toLowerCase().contains("script"));
}
}

/**
Expand All @@ -51,21 +58,12 @@
"NULL, NULL"
}, nullValues = {"NULL"})
public void testSanitizeAdvancedHTML(String unsafe, String safe) {
String sanitizedOutput = MarkupChecker.sanitizeAdvancedHTML(unsafe);

// Normalize both the expected and actual content by removing whitespaces

String normalizedSafe = null;
if (safe != null) {
normalizedSafe = safe.replaceAll("\\s+", "").trim();
String actual = MarkupChecker.sanitizeAdvancedHTML(unsafe);
MarkupCheckerUtil.assertHtmlEqual(safe, actual);
// Sanity check that the key tag we strip is truly gone
if(actual != null) {
assertFalse(actual.toLowerCase().contains("script"));
}

String normalizedOutput = null;
if (sanitizedOutput != null) {
normalizedOutput = sanitizedOutput.replaceAll("\\s+", "").trim();
}

assertEquals(normalizedSafe, normalizedOutput);
}

/**
Expand All @@ -90,5 +88,4 @@
public void testEscapeHtml() {
assertEquals("foo&lt;br&gt;bar", MarkupChecker.escapeHtml("foo<br>bar"));
}

}
97 changes: 97 additions & 0 deletions src/test/java/edu/harvard/iq/dataverse/util/MarkupCheckerUtil.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
package edu.harvard.iq.dataverse.util;

import org.jsoup.Jsoup;


import static org.junit.jupiter.api.Assertions.assertEquals;

public class MarkupCheckerUtil {

/** Test HTML equivalence and ignore differences in the order of attributes
* This does (in normalizeHtml()) use Jsoup to help test Jsoup though.
*
* @param expected - the HTML we expect to be returned
* @param actual - the HTML we actually got
*/
public static void assertHtmlEqual(String expected, String actual) {
if (expected == null || actual == null) {
assertEquals(expected, actual);
return;
}

String normalizedExpected = normalizeHtml(expected);
String normalizedActual = normalizeHtml(actual);
assertEquals(normalizedExpected, normalizedActual);
}

/**
* Creates a Hamcrest matcher that compares HTML after normalization, ignoring
* differences such as attribute ordering and whitespace.
*
* @param expected the expected HTML
* @return a matcher for HTML-equivalent strings
*/
public static org.hamcrest.Matcher<String> htmlEqualTo(String expected) {
return new org.hamcrest.BaseMatcher<String>() {

@Override
public boolean matches(Object actual) {
if (expected == null || actual == null) {
return expected == actual;
}

if (!(actual instanceof String actualHtml)) {
return false;
}

return normalizeHtml(expected).equals(normalizeHtml(actualHtml));
}

@Override
public void describeTo(org.hamcrest.Description description) {
description.appendText("HTML equal to ")
.appendValue(expected);

if (expected != null) {
description.appendText(" after normalization as ")
.appendValue(normalizeHtml(expected));
}
}

@Override
public void describeMismatch(Object actual, org.hamcrest.Description description) {
if (actual == null) {
description.appendText("was null");
return;
}

if (!(actual instanceof String actualHtml)) {
description.appendText("was ")
.appendValue(actual);
return;
}

description.appendText("was ")
.appendValue(actualHtml)
.appendText(" after normalization as ")
.appendValue(normalizeHtml(actualHtml));
}
};
}

private static String normalizeHtml(String html) {
org.jsoup.nodes.Document doc = Jsoup.parseBodyFragment(html);
for (org.jsoup.nodes.Element el : doc.getAllElements()) {
org.jsoup.nodes.Attributes attrs = el.attributes();
java.util.List<org.jsoup.nodes.Attribute> list = new java.util.ArrayList<>(attrs.asList());
list.sort(java.util.Map.Entry.comparingByKey());
for (org.jsoup.nodes.Attribute a : list) {
attrs.remove(a.getKey());
}
for (org.jsoup.nodes.Attribute a : list) {
attrs.put(a);
}
}
return doc.body().html().replaceAll("\\s+", "");
}
}
Loading