Add html file test
This commit is contained in:
parent
ba30654728
commit
7881420cbd
@ -119,9 +119,9 @@ public class MarkwonHtmlParserImpl extends MarkwonHtmlParser {
|
||||
|
||||
private boolean isInsidePreTag;
|
||||
|
||||
private Tokeniser tokeniser;
|
||||
|
||||
private CharacterReader reader;
|
||||
// the thing is: we ensure a new line BEFORE block tag
|
||||
// but not after, so another tag will be placed on the same line (which is wrong)
|
||||
private boolean previousIsBlock;
|
||||
|
||||
|
||||
MarkwonHtmlParserImpl(
|
||||
@ -242,6 +242,8 @@ public class MarkwonHtmlParserImpl extends MarkwonHtmlParser {
|
||||
|
||||
final HtmlTagImpl.InlineImpl inline = new HtmlTagImpl.InlineImpl(name, output.length(), extractAttributes(startTag));
|
||||
|
||||
ensureNewLineIfPreviousWasBlock(output);
|
||||
|
||||
if (isVoidTag(name)
|
||||
|| startTag.selfClosing) {
|
||||
|
||||
@ -305,6 +307,8 @@ public class MarkwonHtmlParserImpl extends MarkwonHtmlParser {
|
||||
if (isBlockTag(name)) {
|
||||
isInsidePreTag = "pre".equals(name);
|
||||
ensureNewLine(output);
|
||||
} else {
|
||||
ensureNewLineIfPreviousWasBlock(output);
|
||||
}
|
||||
|
||||
final int start = output.length();
|
||||
@ -350,6 +354,11 @@ public class MarkwonHtmlParserImpl extends MarkwonHtmlParser {
|
||||
|
||||
block.closeAt(output.length());
|
||||
|
||||
// if it's empty -> we do no care about if it's block or not
|
||||
if (!block.isEmpty()) {
|
||||
previousIsBlock = isBlockTag(block.name);
|
||||
}
|
||||
|
||||
if (TAG_PARAGRAPH.equals(name)) {
|
||||
appendQuietly(output, '\n');
|
||||
}
|
||||
@ -368,6 +377,7 @@ public class MarkwonHtmlParserImpl extends MarkwonHtmlParser {
|
||||
if (isInsidePreTag) {
|
||||
appendQuietly(output, character.getData());
|
||||
} else {
|
||||
ensureNewLineIfPreviousWasBlock(output);
|
||||
trimmingAppender.append(output, character.getData());
|
||||
}
|
||||
}
|
||||
@ -410,6 +420,13 @@ public class MarkwonHtmlParserImpl extends MarkwonHtmlParser {
|
||||
return blockTag;
|
||||
}
|
||||
|
||||
protected <T extends Appendable & CharSequence> void ensureNewLineIfPreviousWasBlock(@NonNull T output) {
|
||||
if (previousIsBlock) {
|
||||
ensureNewLine(output);
|
||||
previousIsBlock = false;
|
||||
}
|
||||
}
|
||||
|
||||
// name here must lower case
|
||||
protected static boolean isInlineTag(@NonNull String name) {
|
||||
return INLINE_TAGS.contains(name);
|
||||
|
@ -833,6 +833,30 @@ public class MarkwonHtmlParserImplTest {
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void newLineAfterBlockTag() {
|
||||
|
||||
final MarkwonHtmlParserImpl impl = MarkwonHtmlParserImpl.create();
|
||||
final StringBuilder output = new StringBuilder();
|
||||
|
||||
final String[] fragments = {
|
||||
"<h1>head #1</h1>just text",
|
||||
"<h2>head #2</h2><span>in span tag</span>",
|
||||
"<h3>head #3</h3><custom-tag>in custom-tag</custom-tag>"
|
||||
};
|
||||
|
||||
for (String fragment: fragments) {
|
||||
impl.processFragment(output, fragment);
|
||||
}
|
||||
|
||||
final String expected = "" +
|
||||
"head #1\njust text\n" +
|
||||
"head #2\nin span tag\n" +
|
||||
"head #3\nin custom-tag";
|
||||
|
||||
assertEquals(expected, output.toString());
|
||||
}
|
||||
|
||||
private static class CaptureTagsAction<T> implements MarkwonHtmlParser.FlushAction<T> {
|
||||
|
||||
boolean called;
|
||||
|
@ -13,6 +13,7 @@ import ru.noties.markwon.SpannableConfiguration;
|
||||
import ru.noties.markwon.html.api.MarkwonHtmlParser;
|
||||
import ru.noties.markwon.renderer.html2.tag.BlockquoteHandler;
|
||||
import ru.noties.markwon.renderer.html2.tag.EmphasisHandler;
|
||||
import ru.noties.markwon.renderer.html2.tag.HeadingHandler;
|
||||
import ru.noties.markwon.renderer.html2.tag.ImageHandler;
|
||||
import ru.noties.markwon.renderer.html2.tag.LinkHandler;
|
||||
import ru.noties.markwon.renderer.html2.tag.ListHandler;
|
||||
@ -69,7 +70,13 @@ public abstract class MarkwonHtmlRenderer {
|
||||
.handler("ul", listHandler)
|
||||
.handler("ol", listHandler)
|
||||
.handler("img", ImageHandler.create())
|
||||
.handler("blockquote", new BlockquoteHandler());
|
||||
.handler("blockquote", new BlockquoteHandler())
|
||||
.handler("h1", new HeadingHandler(1))
|
||||
.handler("h2", new HeadingHandler(2))
|
||||
.handler("h3", new HeadingHandler(3))
|
||||
.handler("h4", new HeadingHandler(4))
|
||||
.handler("h5", new HeadingHandler(5))
|
||||
.handler("h6", new HeadingHandler(6));
|
||||
}
|
||||
|
||||
@NonNull
|
||||
|
@ -0,0 +1,22 @@
|
||||
package ru.noties.markwon.renderer.html2.tag;
|
||||
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
|
||||
import ru.noties.markwon.SpannableConfiguration;
|
||||
import ru.noties.markwon.html.api.HtmlTag;
|
||||
|
||||
public class HeadingHandler extends SimpleTagHandler {
|
||||
|
||||
private final int level;
|
||||
|
||||
public HeadingHandler(int level) {
|
||||
this.level = level;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public Object getSpans(@NonNull SpannableConfiguration configuration, @NonNull HtmlTag tag) {
|
||||
return configuration.factory().heading(configuration.theme(), level);
|
||||
}
|
||||
}
|
@ -11,7 +11,7 @@ public class LinkHandler extends SimpleTagHandler {
|
||||
@Nullable
|
||||
@Override
|
||||
public Object getSpans(@NonNull SpannableConfiguration configuration, @NonNull HtmlTag tag) {
|
||||
final String destination = tag.attributes().get("src");
|
||||
final String destination = tag.attributes().get("href");
|
||||
if (!TextUtils.isEmpty(destination)) {
|
||||
return configuration.factory().link(
|
||||
configuration.theme(),
|
||||
|
@ -1,15 +1,20 @@
|
||||
package ru.noties.markwon.renderer.visitor;
|
||||
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.text.SpannableStringBuilder;
|
||||
|
||||
import org.commonmark.node.Node;
|
||||
import org.junit.ComparisonFailure;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.robolectric.ParameterizedRobolectricTestRunner;
|
||||
import org.robolectric.annotation.Config;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Comparator;
|
||||
import java.util.Map;
|
||||
|
||||
import ix.Ix;
|
||||
import ix.IxPredicate;
|
||||
@ -55,13 +60,16 @@ public class SpannableMarkdownVisitorTest {
|
||||
|
||||
final SpannableStringBuilder stringBuilder = builder.spannableStringBuilder();
|
||||
|
||||
System.out.printf("%n%s%n", stringBuilder);
|
||||
System.out.printf("%s: %s%n", file, Arrays.toString(stringBuilder.getSpans(0, stringBuilder.length(), Object.class)));
|
||||
|
||||
int index = 0;
|
||||
|
||||
for (TestNode testNode : data.output()) {
|
||||
index = validate(stringBuilder, index, testNode);
|
||||
}
|
||||
|
||||
// assert that the whole thing is processed
|
||||
assertEquals(stringBuilder.length(), index);
|
||||
}
|
||||
|
||||
private int validate(@NonNull SpannableStringBuilder builder, int index, @NonNull TestNode node) {
|
||||
@ -103,6 +111,8 @@ public class SpannableMarkdownVisitorTest {
|
||||
|
||||
final String info = node.toString();
|
||||
|
||||
System.out.printf("%s: %s%n", file, builder.subSequence(index, out));
|
||||
|
||||
// we can possibly have parent spans here, should filter them
|
||||
final Object[] spans = builder.getSpans(index, out, Object.class);
|
||||
assertTrue(info, spans != null);
|
||||
@ -123,14 +133,18 @@ public class SpannableMarkdownVisitorTest {
|
||||
})
|
||||
.first(null);
|
||||
|
||||
assertNotNull(info, testSpan);
|
||||
assertNotNull(
|
||||
format("info: %s, spans: %s", info, Arrays.toString(spans)),
|
||||
testSpan
|
||||
);
|
||||
|
||||
assertEquals(info, span.name(), testSpan.name());
|
||||
assertEquals(info, span.attributes(), testSpan.attributes());
|
||||
assertMapEquals(info, span.attributes(), testSpan.attributes());
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
@SuppressWarnings("ConstantConditions")
|
||||
@NonNull
|
||||
private SpannableConfiguration configuration(@NonNull TestConfig config) {
|
||||
|
||||
@ -147,4 +161,49 @@ public class SpannableMarkdownVisitorTest {
|
||||
.factory(factory)
|
||||
.build();
|
||||
}
|
||||
|
||||
private static void assertMapEquals(
|
||||
@NonNull String message,
|
||||
@NonNull Map<String, String> expected,
|
||||
@NonNull Map<String, String> actual) {
|
||||
boolean result = true;
|
||||
if (expected.size() == actual.size()) {
|
||||
for (Map.Entry<String, String> entry : expected.entrySet()) {
|
||||
if (!actual.containsKey(entry.getKey())
|
||||
|| !equals(entry.getValue(), actual.get(entry.getKey()))) {
|
||||
result = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!result) {
|
||||
final Comparator<Map.Entry<String, String>> comparator = new Comparator<Map.Entry<String, String>>() {
|
||||
@Override
|
||||
public int compare(Map.Entry<String, String> o1, Map.Entry<String, String> o2) {
|
||||
return o1.getKey().compareTo(o2.getKey());
|
||||
}
|
||||
};
|
||||
final String e = Ix.from(expected.entrySet())
|
||||
.orderBy(comparator)
|
||||
.toList()
|
||||
.toString();
|
||||
final String a = Ix.from(actual.entrySet())
|
||||
.orderBy(comparator)
|
||||
.toList()
|
||||
.toString();
|
||||
throw new ComparisonFailure(message, e, a);
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean equals(@Nullable Object o1, @Nullable Object o2) {
|
||||
return o1 != null
|
||||
? o1.equals(o2)
|
||||
: o2 == null;
|
||||
|
||||
}
|
||||
|
||||
@NonNull
|
||||
private static String format(@NonNull String message, Object... args) {
|
||||
return String.format(message, args);
|
||||
}
|
||||
}
|
@ -186,7 +186,7 @@ class TestFactory implements SpannableFactory {
|
||||
final int length = pairs.length;
|
||||
final Map<String, String> map = new HashMap<>(length);
|
||||
for (Pair pair : pairs) {
|
||||
map.put(pair.key, String.valueOf(pair.value));
|
||||
map.put(pair.key, pair.value == null ? null : String.valueOf(pair.value));
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
105
markwon/src/test/resources/tests/html.yaml
Normal file
105
markwon/src/test/resources/tests/html.yaml
Normal file
@ -0,0 +1,105 @@
|
||||
input: |-
|
||||
<h1>html</h1>
|
||||
<h2>emphasis</h2>
|
||||
<i>i</i><em>em</em><cite>cite</cite><dfn>dfn</dfn>
|
||||
<h2>strong-emphasis</h2>
|
||||
<b>b</b><strong>strong</strong>
|
||||
<h2>super-script</h2>
|
||||
<sup>sup</sup>
|
||||
<h2>sub-script</h2>
|
||||
<sub>sub</sub>
|
||||
<h2>underline</h2>
|
||||
<u>u</u><ins>ins</ins>
|
||||
<h2>strike</h2>
|
||||
<s>s</s><del>del</del>
|
||||
<h2>link</h2>
|
||||
<a href="a://href">a</a>
|
||||
<h2>unordered-list</h2>
|
||||
<ul><li>ul1<li>ul2</ul>
|
||||
<h2>ordered-list</h2>
|
||||
<ol><li>ol1<li>ol2</ol>
|
||||
<h2>image</h2>
|
||||
<img src="img://src" alt="img">
|
||||
<h2>blockquote</h2>
|
||||
<blockquote>blockquote</blockquote>
|
||||
<h3>3</h3>
|
||||
<h4>4</h4>
|
||||
<h5>5</h5>
|
||||
<h6>6</h6>
|
||||
|
||||
config:
|
||||
use-html: true
|
||||
|
||||
output:
|
||||
- h1: "html"
|
||||
- text: "\n"
|
||||
- h2: "emphasis"
|
||||
- text: "\n"
|
||||
- i: "i"
|
||||
- i: "em"
|
||||
- i: "cite"
|
||||
- i: "dfn"
|
||||
- text: "\n"
|
||||
- h2: "strong-emphasis"
|
||||
- text: "\n"
|
||||
- b: "b"
|
||||
- b: "strong"
|
||||
- text: "\n"
|
||||
- h2: "super-script"
|
||||
- text: "\n"
|
||||
- sup: "sup"
|
||||
- text: "\n"
|
||||
- h2: "sub-script"
|
||||
- text: "\n"
|
||||
- sub: "sub"
|
||||
- text: "\n"
|
||||
- h2: "underline"
|
||||
- text: "\n"
|
||||
- u: "u"
|
||||
- u: "ins"
|
||||
- text: "\n"
|
||||
- h2: "strike"
|
||||
- text: "\n"
|
||||
- s: "s"
|
||||
- s: "del"
|
||||
- text: "\n"
|
||||
- h2: "link"
|
||||
- text: "\n"
|
||||
- a: "a"
|
||||
attrs:
|
||||
href: "a://href"
|
||||
- text: "\n"
|
||||
- h2: "unordered-list"
|
||||
- text: "\n"
|
||||
- ul: "ul1"
|
||||
- text: "\n"
|
||||
- ul: "ul2"
|
||||
- text: "\n"
|
||||
- h2: "ordered-list"
|
||||
- text: "\n"
|
||||
- ol: "ol1"
|
||||
attrs:
|
||||
start: 1
|
||||
- text: "\n"
|
||||
- ol: "ol2"
|
||||
attrs:
|
||||
start: 2
|
||||
- text: "\n"
|
||||
- h2: "image"
|
||||
- text: "\n"
|
||||
- img: "img"
|
||||
attrs:
|
||||
src: "img://src"
|
||||
- text: "\n"
|
||||
- h2: "blockquote"
|
||||
- text: "\n"
|
||||
- blockquote: "blockquote"
|
||||
- text: "\n"
|
||||
- h3: "3"
|
||||
- text: "\n"
|
||||
- h4: "4"
|
||||
- text: "\n"
|
||||
- h5: "5"
|
||||
- text: "\n"
|
||||
- h6: "6"
|
||||
|
@ -3,6 +3,6 @@ input: ""
|
||||
output:
|
||||
- img: "image"
|
||||
attrs:
|
||||
scr: "#href"
|
||||
src: "#href"
|
||||
imageSize: null
|
||||
replacementTextIsLink: false
|
Loading…
x
Reference in New Issue
Block a user