CorePlugin tests
This commit is contained in:
parent
6f8c1dfaee
commit
4c18115b57
@ -155,6 +155,10 @@ class MarkwonBuilderImpl implements Markwon.Builder {
|
|||||||
|
|
||||||
// here we do not check for exact match (a user could've subclasses CorePlugin
|
// here we do not check for exact match (a user could've subclasses CorePlugin
|
||||||
// and supplied it. In this case we DO NOT implicitly add CorePlugin
|
// and supplied it. In this case we DO NOT implicitly add CorePlugin
|
||||||
|
//
|
||||||
|
// if core is present already we do not need to iterate anymore -> as nothing
|
||||||
|
// will be changed (and we actually do not care if there are any dependents of Core
|
||||||
|
// as it's present anyway)
|
||||||
if (CorePlugin.class.isAssignableFrom(plugin.getClass())) {
|
if (CorePlugin.class.isAssignableFrom(plugin.getClass())) {
|
||||||
hasCore = true;
|
hasCore = true;
|
||||||
break;
|
break;
|
||||||
|
@ -11,7 +11,7 @@ import android.support.annotation.Nullable;
|
|||||||
* @see #of(Class, String)
|
* @see #of(Class, String)
|
||||||
* @since 3.0.0
|
* @since 3.0.0
|
||||||
*/
|
*/
|
||||||
public final class Prop<T> {
|
public class Prop<T> {
|
||||||
|
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
@NonNull
|
@NonNull
|
||||||
@ -26,7 +26,7 @@ public final class Prop<T> {
|
|||||||
|
|
||||||
private final String name;
|
private final String name;
|
||||||
|
|
||||||
private Prop(@NonNull String name) {
|
Prop(@NonNull String name) {
|
||||||
this.name = name;
|
this.name = name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -9,7 +9,7 @@ import java.util.Map;
|
|||||||
/**
|
/**
|
||||||
* @since 3.0.0
|
* @since 3.0.0
|
||||||
*/
|
*/
|
||||||
public class RenderPropsImpl implements RenderProps {
|
class RenderPropsImpl implements RenderProps {
|
||||||
|
|
||||||
private final Map<Prop, Object> values = new HashMap<>(3);
|
private final Map<Prop, Object> values = new HashMap<>(3);
|
||||||
|
|
||||||
|
278
markwon/src/test/java/ru/noties/markwon/core/CorePluginTest.java
Normal file
278
markwon/src/test/java/ru/noties/markwon/core/CorePluginTest.java
Normal file
@ -0,0 +1,278 @@
|
|||||||
|
package ru.noties.markwon.core;
|
||||||
|
|
||||||
|
import android.support.annotation.NonNull;
|
||||||
|
import android.support.annotation.Nullable;
|
||||||
|
|
||||||
|
import org.commonmark.node.BlockQuote;
|
||||||
|
import org.commonmark.node.BulletList;
|
||||||
|
import org.commonmark.node.Code;
|
||||||
|
import org.commonmark.node.Emphasis;
|
||||||
|
import org.commonmark.node.FencedCodeBlock;
|
||||||
|
import org.commonmark.node.HardLineBreak;
|
||||||
|
import org.commonmark.node.Heading;
|
||||||
|
import org.commonmark.node.IndentedCodeBlock;
|
||||||
|
import org.commonmark.node.Link;
|
||||||
|
import org.commonmark.node.ListItem;
|
||||||
|
import org.commonmark.node.Node;
|
||||||
|
import org.commonmark.node.OrderedList;
|
||||||
|
import org.commonmark.node.Paragraph;
|
||||||
|
import org.commonmark.node.SoftLineBreak;
|
||||||
|
import org.commonmark.node.StrongEmphasis;
|
||||||
|
import org.commonmark.node.Text;
|
||||||
|
import org.commonmark.node.ThematicBreak;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
import org.mockito.ArgumentCaptor;
|
||||||
|
import org.robolectric.RobolectricTestRunner;
|
||||||
|
import org.robolectric.annotation.Config;
|
||||||
|
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
import java.lang.reflect.Modifier;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import ix.Ix;
|
||||||
|
import ix.IxFunction;
|
||||||
|
import ix.IxPredicate;
|
||||||
|
import ru.noties.markwon.MarkwonConfiguration;
|
||||||
|
import ru.noties.markwon.MarkwonSpansFactory;
|
||||||
|
import ru.noties.markwon.MarkwonVisitor;
|
||||||
|
import ru.noties.markwon.RenderProps;
|
||||||
|
import ru.noties.markwon.SpanFactory;
|
||||||
|
import ru.noties.markwon.SpannableBuilder;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertNotNull;
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
|
import static org.mockito.ArgumentMatchers.any;
|
||||||
|
import static org.mockito.ArgumentMatchers.eq;
|
||||||
|
import static org.mockito.Mockito.mock;
|
||||||
|
import static org.mockito.Mockito.times;
|
||||||
|
import static org.mockito.Mockito.verify;
|
||||||
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
|
@RunWith(RobolectricTestRunner.class)
|
||||||
|
@Config(manifest = Config.NONE)
|
||||||
|
public class CorePluginTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void visitors_registered() {
|
||||||
|
|
||||||
|
// only these must be registered (everything else is an error)
|
||||||
|
// Paragraph has registered visitor but no Span by default
|
||||||
|
|
||||||
|
//noinspection unchecked
|
||||||
|
final Class<? extends Node>[] expected = new Class[]{
|
||||||
|
BlockQuote.class,
|
||||||
|
BulletList.class,
|
||||||
|
Code.class,
|
||||||
|
Emphasis.class,
|
||||||
|
FencedCodeBlock.class,
|
||||||
|
HardLineBreak.class,
|
||||||
|
Heading.class,
|
||||||
|
IndentedCodeBlock.class,
|
||||||
|
Link.class,
|
||||||
|
ListItem.class,
|
||||||
|
OrderedList.class,
|
||||||
|
Paragraph.class,
|
||||||
|
SoftLineBreak.class,
|
||||||
|
StrongEmphasis.class,
|
||||||
|
Text.class,
|
||||||
|
ThematicBreak.class
|
||||||
|
};
|
||||||
|
|
||||||
|
final CorePlugin plugin = CorePlugin.create();
|
||||||
|
|
||||||
|
final class BuilderImpl implements MarkwonVisitor.Builder {
|
||||||
|
|
||||||
|
private final Map<Class<? extends Node>, MarkwonVisitor.NodeVisitor> map =
|
||||||
|
new HashMap<>();
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
@Override
|
||||||
|
public <N extends Node> MarkwonVisitor.Builder on(@NonNull Class<N> node, @Nullable MarkwonVisitor.NodeVisitor<? super N> nodeVisitor) {
|
||||||
|
if (map.put(node, nodeVisitor) != null) {
|
||||||
|
throw new RuntimeException("Multiple visitors registered for the node: " + node.getClass().getName());
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
@Override
|
||||||
|
public MarkwonVisitor build(@NonNull MarkwonConfiguration configuration, @NonNull RenderProps renderProps) {
|
||||||
|
throw new RuntimeException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
final BuilderImpl impl = new BuilderImpl();
|
||||||
|
|
||||||
|
plugin.configureVisitor(impl);
|
||||||
|
|
||||||
|
for (Class<? extends Node> node : expected) {
|
||||||
|
assertNotNull("Node visitor registered: " + node.getName(), impl.map.remove(node));
|
||||||
|
}
|
||||||
|
|
||||||
|
// all other nodes (that could've been registered is an error)
|
||||||
|
assertEquals(impl.map.toString(), 0, impl.map.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void spans_registered() {
|
||||||
|
|
||||||
|
// paragraph has visitor registered, but no span associated by default
|
||||||
|
|
||||||
|
//noinspection unchecked
|
||||||
|
final Class<? extends Node>[] expected = new Class[]{
|
||||||
|
BlockQuote.class,
|
||||||
|
Code.class,
|
||||||
|
Emphasis.class,
|
||||||
|
FencedCodeBlock.class,
|
||||||
|
Heading.class,
|
||||||
|
IndentedCodeBlock.class,
|
||||||
|
Link.class,
|
||||||
|
ListItem.class,
|
||||||
|
StrongEmphasis.class,
|
||||||
|
ThematicBreak.class
|
||||||
|
};
|
||||||
|
|
||||||
|
final CorePlugin plugin = CorePlugin.create();
|
||||||
|
|
||||||
|
final class BuilderImpl implements MarkwonSpansFactory.Builder {
|
||||||
|
|
||||||
|
private final Map<Class<? extends Node>, SpanFactory> map =
|
||||||
|
new HashMap<>();
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
@Override
|
||||||
|
public <N extends Node> MarkwonSpansFactory.Builder setFactory(@NonNull Class<N> node, @NonNull SpanFactory factory) {
|
||||||
|
if (map.put(node, factory) != null) {
|
||||||
|
throw new RuntimeException("Multiple SpanFactories registered for the node: " + node.getName());
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
@Override
|
||||||
|
public MarkwonSpansFactory build() {
|
||||||
|
throw new RuntimeException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
final BuilderImpl impl = new BuilderImpl();
|
||||||
|
|
||||||
|
plugin.configureSpansFactory(impl);
|
||||||
|
|
||||||
|
for (Class<? extends Node> node : expected) {
|
||||||
|
assertNotNull("SpanFactory registered: " + node.getName(), impl.map.remove(node));
|
||||||
|
}
|
||||||
|
|
||||||
|
assertEquals(impl.map.toString(), 0, impl.map.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void priority_none() {
|
||||||
|
// CorePlugin returns none as priority (thus 0)
|
||||||
|
|
||||||
|
assertEquals(0, CorePlugin.create().priority().after().size());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void plugin_methods() {
|
||||||
|
// checks that only expected plugin methods are overridden
|
||||||
|
|
||||||
|
// these represent actual methods that are present (we expect them to be present)
|
||||||
|
final Set<String> usedMethods = new HashSet<String>() {{
|
||||||
|
add("configureVisitor");
|
||||||
|
add("configureSpansFactory");
|
||||||
|
add("beforeSetText");
|
||||||
|
add("priority");
|
||||||
|
}};
|
||||||
|
|
||||||
|
// we will use declaredMethods because it won't return inherited ones
|
||||||
|
final Method[] declaredMethods = CorePlugin.class.getDeclaredMethods();
|
||||||
|
assertNotNull(declaredMethods);
|
||||||
|
assertTrue(declaredMethods.length > 0);
|
||||||
|
|
||||||
|
final List<String> methods = Ix.fromArray(declaredMethods)
|
||||||
|
.filter(new IxPredicate<Method>() {
|
||||||
|
@Override
|
||||||
|
public boolean test(Method method) {
|
||||||
|
// ignore private, static
|
||||||
|
final int modifiers = method.getModifiers();
|
||||||
|
return !Modifier.isStatic(modifiers)
|
||||||
|
&& !Modifier.isPrivate(modifiers);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.map(new IxFunction<Method, String>() {
|
||||||
|
@Override
|
||||||
|
public String apply(Method method) {
|
||||||
|
return method.getName();
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.filter(new IxPredicate<String>() {
|
||||||
|
@Override
|
||||||
|
public boolean test(String s) {
|
||||||
|
return !usedMethods.contains(s);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.toList();
|
||||||
|
|
||||||
|
assertEquals(methods.toString(), 0, methods.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void softbreak_adds_new_line_default() {
|
||||||
|
// default is false
|
||||||
|
softbreak_adds_new_line(CorePlugin.create(), false);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void softbreak_adds_new_line_false() {
|
||||||
|
// a space character will be added
|
||||||
|
softbreak_adds_new_line(CorePlugin.create(false), false);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void softbreak_adds_new_line_true() {
|
||||||
|
// a new line will be added
|
||||||
|
softbreak_adds_new_line(CorePlugin.create(true), true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void softbreak_adds_new_line(
|
||||||
|
@NonNull CorePlugin plugin,
|
||||||
|
boolean softBreakAddsNewLine) {
|
||||||
|
|
||||||
|
final MarkwonVisitor.Builder builder = mock(MarkwonVisitor.Builder.class);
|
||||||
|
when(builder.on(any(Class.class), any(MarkwonVisitor.NodeVisitor.class))).thenReturn(builder);
|
||||||
|
|
||||||
|
final ArgumentCaptor<MarkwonVisitor.NodeVisitor> captor =
|
||||||
|
ArgumentCaptor.forClass(MarkwonVisitor.NodeVisitor.class);
|
||||||
|
|
||||||
|
plugin.configureVisitor(builder);
|
||||||
|
|
||||||
|
//noinspection unchecked
|
||||||
|
verify(builder).on(eq(SoftLineBreak.class), captor.capture());
|
||||||
|
|
||||||
|
//noinspection unchecked
|
||||||
|
final MarkwonVisitor.NodeVisitor<SoftLineBreak> nodeVisitor = captor.getValue();
|
||||||
|
final MarkwonVisitor visitor = mock(MarkwonVisitor.class);
|
||||||
|
|
||||||
|
if (!softBreakAddsNewLine) {
|
||||||
|
|
||||||
|
// we must mock SpannableBuilder and verify that it has a space character appended
|
||||||
|
final SpannableBuilder spannableBuilder = mock(SpannableBuilder.class);
|
||||||
|
when(visitor.builder()).thenReturn(spannableBuilder);
|
||||||
|
nodeVisitor.visit(visitor, mock(SoftLineBreak.class));
|
||||||
|
|
||||||
|
verify(visitor, times(1)).builder();
|
||||||
|
verify(spannableBuilder, times(1)).append(eq(' '));
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
nodeVisitor.visit(visitor, mock(SoftLineBreak.class));
|
||||||
|
|
||||||
|
verify(visitor, times(1)).ensureNewLine();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user