aboutsummaryrefslogtreecommitdiffstats
path: root/sonar-testing-harness
diff options
context:
space:
mode:
authorSébastien Lesaint <sebastien.lesaint@sonarsource.com>2019-04-16 15:18:55 +0200
committersonartech <sonartech@sonarsource.com>2019-04-23 10:37:56 +0200
commitd9e7cb020409491b45199ab8762eb22746e3543d (patch)
treec6cd40d4b214f1bb9a2621fa7268cede2de206ca /sonar-testing-harness
parenta5bf96e1bb48375f63420e2bfe87b097033f664f (diff)
downloadsonarqube-d9e7cb020409491b45199ab8762eb22746e3543d.tar.gz
sonarqube-d9e7cb020409491b45199ab8762eb22746e3543d.zip
SONAR-11757 add HtmlFragmentAssert and MimeMessageAssert
Diffstat (limited to 'sonar-testing-harness')
-rw-r--r--sonar-testing-harness/build.gradle4
-rw-r--r--sonar-testing-harness/src/main/java/org/sonar/test/html/HtmlBlockAssert.java130
-rw-r--r--sonar-testing-harness/src/main/java/org/sonar/test/html/HtmlFragmentAssert.java78
-rw-r--r--sonar-testing-harness/src/main/java/org/sonar/test/html/HtmlListAssert.java130
-rw-r--r--sonar-testing-harness/src/main/java/org/sonar/test/html/HtmlParagraphAssert.java220
-rw-r--r--sonar-testing-harness/src/main/java/org/sonar/test/html/MimeMessageAssert.java89
-rw-r--r--sonar-testing-harness/src/main/java/org/sonar/test/html/package-info.java23
7 files changed, 673 insertions, 1 deletions
diff --git a/sonar-testing-harness/build.gradle b/sonar-testing-harness/build.gradle
index a8bc3f4290b..c5001fbcfbd 100644
--- a/sonar-testing-harness/build.gradle
+++ b/sonar-testing-harness/build.gradle
@@ -10,12 +10,14 @@ dependencies {
compile 'com.google.code.gson:gson'
compile 'com.googlecode.json-simple:json-simple'
compile 'commons-io:commons-io'
+ compile 'javax.mail:mail'
compile 'junit:junit'
+ compile 'org.assertj:assertj-core'
compile 'org.hamcrest:hamcrest-all'
+ compile 'org.jsoup:jsoup:1.11.3'
compileOnly 'com.google.code.findbugs:jsr305'
- testCompile 'org.assertj:assertj-core'
}
artifactoryPublish.skip = false
diff --git a/sonar-testing-harness/src/main/java/org/sonar/test/html/HtmlBlockAssert.java b/sonar-testing-harness/src/main/java/org/sonar/test/html/HtmlBlockAssert.java
new file mode 100644
index 00000000000..c0471077e18
--- /dev/null
+++ b/sonar-testing-harness/src/main/java/org/sonar/test/html/HtmlBlockAssert.java
@@ -0,0 +1,130 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.test.html;
+
+import java.util.stream.Collectors;
+import org.assertj.core.api.AbstractAssert;
+import org.assertj.core.api.Assertions;
+import org.jsoup.nodes.Element;
+import org.jsoup.select.Elements;
+
+import static org.assertj.core.util.Preconditions.checkArgument;
+
+public abstract class HtmlBlockAssert<T extends HtmlBlockAssert<T>> extends AbstractAssert<T, Element> {
+ static final String PRINT_FRAGMENT_TEMPLATE = "\n---fragment---\n%s\n---fragment---";
+ private static final String NO_LINK_IN_BLOC = "no link in bloc";
+
+ public HtmlBlockAssert(Element v, Class<T> selfType) {
+ super(v, selfType);
+ }
+
+ /**
+ * Verifies the current block contains a single link with the specified piece of text.
+ */
+ public T withLinkOn(String linkText) {
+ return withLinkOn(linkText, 1);
+ }
+
+ /**
+ * Verifies the current block contains {@code times} links with the specified piece of text.
+ */
+ public T withLinkOn(String linkText, int times) {
+ checkArgument(times >= 1, "times must be >= 1");
+
+ isNotNull();
+
+ Elements as = actual.select("a");
+ Assertions.assertThat(as)
+ .describedAs(NO_LINK_IN_BLOC + PRINT_FRAGMENT_TEMPLATE, actual)
+ .isNotEmpty();
+
+ long count = as.stream().filter(t -> linkText.equals(t.text())).count();
+ if (count != times) {
+ failWithMessage("link on text \"%s\" found %s times in bloc (expected %s). \n Got: %s", linkText, count, times, asyncToString(as));
+ }
+
+ return myself;
+ }
+
+ /**
+ * Verifies the current block contains a link with the specified text and href.
+ */
+ public T withLink(String linkText, String href) {
+ isNotNull();
+
+ Elements as = actual.select("a");
+ Assertions.assertThat(as)
+ .describedAs(NO_LINK_IN_BLOC)
+ .isNotEmpty();
+
+ if (as.stream().noneMatch(t -> linkText.equals(t.text()) && href.equals(t.attr("href")))) {
+ failWithMessage(
+ "link with text \"%s\" and href \"%s\" not found in block. \n Got: %s",
+ linkText, href, asyncToString(as));
+ }
+
+ return myself;
+ }
+
+ public T withoutLink() {
+ isNotNull();
+
+ Assertions.assertThat(actual.select("a")).isEmpty();
+
+ return myself;
+ }
+
+ private static Object asyncToString(Elements as) {
+ return new Object() {
+ @Override
+ public String toString() {
+ return as.stream()
+ .map(a -> "< href=\"" + a.attr("href") + "\">" + a.text() + "<a>")
+ .collect(Collectors.joining("\n"));
+ }
+ };
+ }
+
+ public T withEmphasisOn(String emphasisText) {
+ isNotNull();
+
+ Elements emphases = actual.select("em");
+ Assertions.assertThat(emphases)
+ .describedAs("no <em> in block")
+ .isNotEmpty();
+ Assertions.assertThat(emphases.stream().map(Element::text))
+ .contains(emphasisText);
+
+ return myself;
+ }
+
+ public T withSmallOn(String emphasisText) {
+ isNotNull();
+
+ Elements smalls = actual.select("small");
+ Assertions.assertThat(smalls)
+ .describedAs("no <small> in block")
+ .isNotEmpty();
+ Assertions.assertThat(smalls.stream().map(Element::text))
+ .contains(emphasisText);
+
+ return myself;
+ }
+}
diff --git a/sonar-testing-harness/src/main/java/org/sonar/test/html/HtmlFragmentAssert.java b/sonar-testing-harness/src/main/java/org/sonar/test/html/HtmlFragmentAssert.java
new file mode 100644
index 00000000000..3054112afb5
--- /dev/null
+++ b/sonar-testing-harness/src/main/java/org/sonar/test/html/HtmlFragmentAssert.java
@@ -0,0 +1,78 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.test.html;
+
+import java.util.Iterator;
+import org.assertj.core.api.AbstractAssert;
+import org.assertj.core.api.Assertions;
+import org.jsoup.Jsoup;
+import org.jsoup.nodes.Document;
+import org.jsoup.nodes.Element;
+
+import static java.util.stream.Collectors.toList;
+import static org.sonar.test.html.HtmlParagraphAssert.verifyIsParagraph;
+
+public class HtmlFragmentAssert extends AbstractAssert<HtmlFragmentAssert, String> {
+
+ public HtmlFragmentAssert(String s) {
+ super(s, HtmlFragmentAssert.class);
+ }
+
+ public static HtmlFragmentAssert assertThat(String s) {
+ return new HtmlFragmentAssert(s);
+ }
+
+ public HtmlParagraphAssert hasParagraph() {
+ isNotNull();
+
+ Document document = Jsoup.parseBodyFragment(actual);
+ Iterator<Element> blockIt = document.body().children().stream()
+ .filter(Element::isBlock)
+ .collect(toList())
+ .iterator();
+ Assertions.assertThat(blockIt.hasNext())
+ .describedAs("no bloc in fragment")
+ .isTrue();
+
+ Element firstBlock = blockIt.next();
+ verifyIsParagraph(firstBlock);
+
+ return new HtmlParagraphAssert(firstBlock, blockIt);
+ }
+
+ /**
+ * Convenience method.
+ * Sames as {@code hasParagraph().withText(text)}.
+ */
+ public HtmlParagraphAssert hasParagraph(String text) {
+ return hasParagraph()
+ .withText(text);
+ }
+
+ /**
+ * Convenience method.
+ * Sames as {@code hasParagraph().withLines(line1, line2, ...)}.
+ */
+ public HtmlParagraphAssert hasParagraph(String firstLine, String... otherLines) {
+ return hasParagraph()
+ .withLines(firstLine, otherLines);
+ }
+
+}
diff --git a/sonar-testing-harness/src/main/java/org/sonar/test/html/HtmlListAssert.java b/sonar-testing-harness/src/main/java/org/sonar/test/html/HtmlListAssert.java
new file mode 100644
index 00000000000..87de54c2465
--- /dev/null
+++ b/sonar-testing-harness/src/main/java/org/sonar/test/html/HtmlListAssert.java
@@ -0,0 +1,130 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.test.html;
+
+import java.util.Arrays;
+import java.util.Iterator;
+import java.util.List;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+import org.assertj.core.api.Assertions;
+import org.jsoup.nodes.Element;
+
+public class HtmlListAssert extends HtmlBlockAssert<HtmlListAssert> {
+ private final Iterator<Element> nextBlocks;
+
+ public HtmlListAssert(Element list, Iterator<Element> nextBlocks) {
+ super(list, HtmlListAssert.class);
+ this.nextBlocks = nextBlocks;
+ }
+
+ static void verifyIsList(Element element) {
+ Assertions.assertThat(element.tagName())
+ .describedAs(
+ "next block is neither a <%s> nor a <%s> (got <%s>):" + PRINT_FRAGMENT_TEMPLATE,
+ "ul", "ol", element.tagName(), element.toString())
+ .isIn("ul", "ol");
+ }
+
+ /**
+ * Verifies the text of every items in the current list is equal to the specified strings, in order.
+ */
+ public HtmlListAssert withItemTexts(String firstItemText, String... otherItemsText) {
+ isNotNull();
+
+ List<String> itemsText = actual.children()
+ .stream()
+ .filter(t -> t.tagName().equals("li"))
+ .map(Element::text)
+ .collect(Collectors.toList());
+
+ String[] itemTexts = Stream.concat(
+ Stream.of(firstItemText),
+ Arrays.stream(otherItemsText))
+ .toArray(String[]::new);
+ Assertions.assertThat(itemsText)
+ .describedAs(PRINT_FRAGMENT_TEMPLATE, actual)
+ .containsOnly(itemTexts);
+
+ return this;
+ }
+
+ public HtmlListAssert hasList() {
+ isNotNull();
+
+ Assertions.assertThat(nextBlocks.hasNext())
+ .describedAs("no more block")
+ .isTrue();
+
+ Element element = nextBlocks.next();
+ verifyIsList(element);
+
+ return new HtmlListAssert(element, nextBlocks);
+ }
+
+ /**
+ * Convenience method.
+ * Sames as {@code hasParagraph().withText(text)}.
+ */
+ public HtmlParagraphAssert hasParagraph(String text) {
+ return hasParagraph()
+ .withText(text);
+ }
+
+ /**
+ * Convenience method.
+ * Sames as {@code hasParagraph().withText("")}.
+ */
+ public HtmlParagraphAssert hasEmptyParagraph() {
+ return hasParagraph()
+ .withText("");
+ }
+
+ public HtmlParagraphAssert hasParagraph() {
+ isNotNull();
+
+ Assertions.assertThat(nextBlocks.hasNext())
+ .describedAs("no more block")
+ .isTrue();
+
+ Element element = nextBlocks.next();
+ HtmlParagraphAssert.verifyIsParagraph(element);
+
+ return new HtmlParagraphAssert(element, nextBlocks);
+ }
+
+ /**
+ * Verifies there is no more list in the block.
+ */
+ public void noMoreBlock() {
+ isNotNull();
+
+ Assertions.assertThat(nextBlocks.hasNext())
+ .describedAs("there are still some block. Next one:" + PRINT_FRAGMENT_TEMPLATE,
+ new Object() {
+ @Override
+ public String toString() {
+ return nextBlocks.next().toString();
+ }
+ })
+ .isFalse();
+ }
+
+}
diff --git a/sonar-testing-harness/src/main/java/org/sonar/test/html/HtmlParagraphAssert.java b/sonar-testing-harness/src/main/java/org/sonar/test/html/HtmlParagraphAssert.java
new file mode 100644
index 00000000000..bf7210afa33
--- /dev/null
+++ b/sonar-testing-harness/src/main/java/org/sonar/test/html/HtmlParagraphAssert.java
@@ -0,0 +1,220 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.test.html;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
+import java.util.stream.Stream;
+import org.assertj.core.api.Assertions;
+import org.jsoup.nodes.Element;
+import org.jsoup.nodes.Node;
+import org.jsoup.nodes.TextNode;
+
+import static java.util.Collections.emptyList;
+
+public class HtmlParagraphAssert extends HtmlBlockAssert<HtmlParagraphAssert> {
+ private final Iterator<Element> nextBlocks;
+
+ public HtmlParagraphAssert(Element paragraph, Iterator<Element> nextBlocks) {
+ super(paragraph, HtmlParagraphAssert.class);
+ this.nextBlocks = nextBlocks;
+ }
+
+ static void verifyIsParagraph(Element element) {
+ Assertions.assertThat(element.tagName())
+ .describedAs(
+ "next block is not a <%s> (got <%s>):" + PRINT_FRAGMENT_TEMPLATE,
+ "p", element.tagName(), element.toString())
+ .isEqualTo("p");
+ }
+
+ /**
+ * Verify the next block exists, is a paragraph and returns an Assert on this block.
+ */
+ public HtmlParagraphAssert hasParagraph() {
+ isNotNull();
+
+ Assertions.assertThat(nextBlocks.hasNext())
+ .describedAs("no more bloc")
+ .isTrue();
+
+ Element element = nextBlocks.next();
+ verifyIsParagraph(element);
+
+ return new HtmlParagraphAssert(element, nextBlocks);
+ }
+
+ /**
+ * Convenience method.
+ * Sames as {@code hasParagraph().withText(text)}.
+ */
+ public HtmlParagraphAssert hasParagraph(String text) {
+ return hasParagraph()
+ .withText(text);
+ }
+
+ /**
+ * Convenience method.
+ * Sames as {@code hasParagraph().withText("")}.
+ */
+ public HtmlParagraphAssert hasEmptyParagraph() {
+ return hasParagraph()
+ .withText("");
+ }
+
+ /**
+ * Convenience method.
+ * Sames as {@code hasParagraph().withLines(line1, line2, ...)}.
+ */
+ public HtmlParagraphAssert hasParagraph(String firstLine, String... otherLines) {
+ return hasParagraph()
+ .withLines(firstLine, otherLines);
+ }
+
+ /**
+ * Verifies there is no more block.
+ */
+ public void noMoreBlock() {
+ isNotNull();
+
+ Assertions.assertThat(nextBlocks.hasNext())
+ .describedAs("there are still some paragraph. Next one:" + PRINT_FRAGMENT_TEMPLATE,
+ new Object() {
+ @Override
+ public String toString() {
+ return nextBlocks.next().toString();
+ }
+ })
+ .isFalse();
+ }
+
+ /**
+ * Verifies the current block as the specified text, ignoring lines.
+ */
+ public HtmlParagraphAssert withText(String text) {
+ isNotNull();
+
+ Assertions.assertThat(actual.text())
+ .describedAs(PRINT_FRAGMENT_TEMPLATE, actual)
+ .isEqualTo(text);
+
+ return this;
+ }
+
+ /**
+ * Verifies the current block has all and only the specified lines, in order.
+ */
+ public HtmlParagraphAssert withLines(String firstLine, String... otherLines) {
+ isNotNull();
+
+ List<String> actualLines = toLines(actual);
+ String[] expectedLines = Stream.concat(
+ Stream.of(firstLine),
+ Arrays.stream(otherLines))
+ .toArray(String[]::new);
+
+ Assertions.assertThat(actualLines)
+ .describedAs(PRINT_FRAGMENT_TEMPLATE, actual)
+ .containsExactly(expectedLines);
+
+ return this;
+ }
+
+ /**
+ * Verifies the current block has all and only the specified lines, in any order.
+ */
+ public HtmlParagraphAssert withLines(Set<String> lines) {
+ isNotNull();
+
+ List<String> actualLines = toLines(actual);
+ String[] expectedLines = lines.toArray(new String[0]);
+
+ Assertions.assertThat(actualLines)
+ .describedAs(PRINT_FRAGMENT_TEMPLATE, actual)
+ .containsOnly(expectedLines);
+
+ return this;
+ }
+
+ private static List<String> toLines(Element parent) {
+ Iterator<Node> iterator = parent.childNodes().iterator();
+ if (!iterator.hasNext()) {
+ return emptyList();
+ }
+
+ List<String> actualLines = new ArrayList<>(parent.childNodeSize());
+ StringBuilder currentLine = null;
+ while (iterator.hasNext()) {
+ Node node = iterator.next();
+ if (node instanceof TextNode) {
+ if (currentLine == null) {
+ currentLine = new StringBuilder(node.toString());
+ } else {
+ currentLine.append(node.toString());
+ }
+ } else if (node instanceof Element) {
+ Element element = (Element) node;
+ if (element.tagName().equals("br")) {
+ actualLines.add(currentLine == null ? "" : currentLine.toString());
+ currentLine = null;
+ } else {
+ if (currentLine == null) {
+ currentLine = new StringBuilder(element.text());
+ } else {
+ currentLine.append(element.text());
+ }
+ }
+ } else {
+ throw new IllegalStateException("unsupported node " + node.getClass());
+ }
+
+ if (!iterator.hasNext()) {
+ actualLines.add(currentLine == null ? "" : currentLine.toString());
+ currentLine = null;
+ }
+ }
+ return actualLines;
+ }
+
+ /**
+ * Convenience method.
+ * Same as {@code hasList().withItemTexts("foo", "bar")}.
+ */
+ public HtmlListAssert hasList(String firstItemText, String... otherItemsText) {
+ return hasList()
+ .withItemTexts(firstItemText, otherItemsText);
+ }
+
+ public HtmlListAssert hasList() {
+ isNotNull();
+
+ Assertions.assertThat(nextBlocks.hasNext())
+ .describedAs("no more block")
+ .isTrue();
+
+ Element element = nextBlocks.next();
+ HtmlListAssert.verifyIsList(element);
+
+ return new HtmlListAssert(element, nextBlocks);
+ }
+}
diff --git a/sonar-testing-harness/src/main/java/org/sonar/test/html/MimeMessageAssert.java b/sonar-testing-harness/src/main/java/org/sonar/test/html/MimeMessageAssert.java
new file mode 100644
index 00000000000..faa654b562a
--- /dev/null
+++ b/sonar-testing-harness/src/main/java/org/sonar/test/html/MimeMessageAssert.java
@@ -0,0 +1,89 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.test.html;
+
+import java.io.IOException;
+import javax.mail.MessagingException;
+import javax.mail.internet.MimeMessage;
+import javax.mail.internet.MimeMultipart;
+import org.assertj.core.api.AbstractAssert;
+import org.assertj.core.api.Assertions;
+
+public final class MimeMessageAssert extends AbstractAssert<MimeMessageAssert, MimeMessage> {
+
+ public MimeMessageAssert(MimeMessage mimeMessage) {
+ super(mimeMessage, MimeMessageAssert.class);
+ }
+
+ public static MimeMessageAssert assertThat(MimeMessage m) {
+ return new MimeMessageAssert(m);
+ }
+
+ public HtmlFragmentAssert isHtml() {
+ isNotNull();
+
+ try {
+ Object content = actual.getContent();
+ Assertions.assertThat(content).isInstanceOf(MimeMultipart.class);
+ MimeMultipart m = (MimeMultipart) content;
+ Assertions.assertThat(m.getCount()).isEqualTo(1);
+ return new HtmlFragmentAssert((String) m.getBodyPart(0).getContent());
+ } catch (MessagingException | IOException e) {
+ throw new IllegalStateException(e);
+ }
+ }
+
+ public MimeMessageAssert hasRecipient(String userEmail) {
+ isNotNull();
+
+ try {
+ Assertions.assertThat(actual.getHeader("To", null)).isEqualTo(String.format("<%s>", userEmail));
+ } catch (MessagingException e) {
+ throw new IllegalStateException(e);
+ }
+
+ return this;
+ }
+
+ public MimeMessageAssert hasSubject(String text) {
+ isNotNull();
+
+ try {
+ Assertions.assertThat(actual.getSubject()).isEqualTo(text);
+ } catch (MessagingException e) {
+ throw new IllegalStateException(e);
+ }
+
+ return this;
+ }
+
+ public MimeMessageAssert subjectContains(String text) {
+ isNotNull();
+
+ try {
+ Assertions.assertThat(actual.getSubject()).contains(text);
+ } catch (MessagingException e) {
+ throw new IllegalStateException(e);
+ }
+
+ return this;
+ }
+
+}
diff --git a/sonar-testing-harness/src/main/java/org/sonar/test/html/package-info.java b/sonar-testing-harness/src/main/java/org/sonar/test/html/package-info.java
new file mode 100644
index 00000000000..6bed9071e0e
--- /dev/null
+++ b/sonar-testing-harness/src/main/java/org/sonar/test/html/package-info.java
@@ -0,0 +1,23 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+@ParametersAreNonnullByDefault
+package org.sonar.test.html;
+
+import javax.annotation.ParametersAreNonnullByDefault;