aboutsummaryrefslogtreecommitdiff
path: root/libs/editor/example/src/test/java/org/wordpress/android/editor/HtmlStyleTextWatcherTest.java
diff options
context:
space:
mode:
Diffstat (limited to 'libs/editor/example/src/test/java/org/wordpress/android/editor/HtmlStyleTextWatcherTest.java')
-rw-r--r--libs/editor/example/src/test/java/org/wordpress/android/editor/HtmlStyleTextWatcherTest.java496
1 files changed, 496 insertions, 0 deletions
diff --git a/libs/editor/example/src/test/java/org/wordpress/android/editor/HtmlStyleTextWatcherTest.java b/libs/editor/example/src/test/java/org/wordpress/android/editor/HtmlStyleTextWatcherTest.java
new file mode 100644
index 000000000..beaabe31c
--- /dev/null
+++ b/libs/editor/example/src/test/java/org/wordpress/android/editor/HtmlStyleTextWatcherTest.java
@@ -0,0 +1,496 @@
+package org.wordpress.android.editor;
+
+import android.text.Editable;
+import android.text.Spannable;
+import android.text.SpannableStringBuilder;
+import android.text.style.ForegroundColorSpan;
+import android.text.style.RelativeSizeSpan;
+import android.text.style.StyleSpan;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.annotation.Config;
+
+import static org.junit.Assert.assertEquals;
+
+@Config(sdk = 18)
+@RunWith(RobolectricTestRunner.class)
+public class HtmlStyleTextWatcherTest {
+
+ private HtmlStyleTextWatcherForTests mWatcher;
+ private Editable mContent;
+ private boolean mUpdateSpansWasCalled;
+ private HtmlStyleTextWatcher.SpanRange mSpanRange;
+
+ @Before
+ public void setUp() {
+ mWatcher = new HtmlStyleTextWatcherForTests();
+ mUpdateSpansWasCalled = false;
+ }
+
+ @Test
+ public void testTypingNormalText() {
+ // -- Test typing in normal text (non-HTML) in an empty document
+ mContent = new SpannableStringBuilder("a");
+
+ mWatcher.onTextChanged(mContent, 0, 0, 1); // Typed "a"
+ mWatcher.afterTextChanged(mContent);
+
+ assertEquals(false, mUpdateSpansWasCalled);
+
+ mContent = new SpannableStringBuilder("ab");
+
+ mWatcher.onTextChanged(mContent, 1, 0, 1); // Typed "b"
+ mWatcher.afterTextChanged(mContent);
+
+ assertEquals(false, mUpdateSpansWasCalled);
+
+
+ // -- Test typing in normal text after exiting tags
+ mContent = new SpannableStringBuilder("text <b>bold</b> a");
+
+ mWatcher.onTextChanged(mContent, 17, 0, 1); // Typed "a"
+ mWatcher.afterTextChanged(mContent);
+
+ assertEquals(false, mUpdateSpansWasCalled);
+
+
+ // -- Test typing in normal text before exiting tags
+ mContent = new SpannableStringBuilder("text a <b>bold</b>");
+
+ mWatcher.onTextChanged(mContent, 5, 0, 1); // Typed "a"
+ mWatcher.afterTextChanged(mContent);
+
+ assertEquals(false, mUpdateSpansWasCalled);
+ }
+
+ @Test
+ public void testTypingInOpeningTag() {
+ // Test with several different cases of pre-existing text
+ String[] previousTextCases = new String[]{"", "plain text", "<i>",
+ "<blockquote>some existing content</blockquote> "};
+ for (String initialText : previousTextCases) {
+ int offset = initialText.length();
+ mUpdateSpansWasCalled = false;
+
+ // -- Test typing in an opening tag symbol
+ mContent = new SpannableStringBuilder(initialText + "<");
+
+ mWatcher.onTextChanged(mContent, offset, 0, 1);
+ mWatcher.afterTextChanged(mContent);
+
+ // No formatting should be applied/removed
+ assertEquals(false, mUpdateSpansWasCalled);
+
+
+ // -- Test typing in the tag name
+ mContent = new SpannableStringBuilder(initialText + "<b");
+
+ mWatcher.onTextChanged(mContent, offset + 1, 0, 1);
+ mWatcher.afterTextChanged(mContent);
+
+ // No formatting should be applied/removed
+ assertEquals(false, mUpdateSpansWasCalled);
+
+
+ // -- Test typing in a closing tag symbol
+ mContent = new SpannableStringBuilder(initialText + "<b>");
+
+ mWatcher.onTextChanged(mContent, offset + 2, 0, 1);
+ mWatcher.afterTextChanged(mContent);
+
+ assertEquals(offset, mSpanRange.getOpeningTagLoc());
+ assertEquals(offset + 3, mSpanRange.getClosingTagLoc());
+ }
+ }
+
+ @Test
+ public void testTypingInClosingTag() {
+ // Test with several different cases of pre-existing text
+ String[] previousTextCases = new String[]{"<b>stuff", "plain text <b>stuff", "<i><b>stuff",
+ "<blockquote>some existing content</blockquote> <b>stuff"};
+
+ for (String initialText : previousTextCases) {
+ int offset = initialText.length();
+ mUpdateSpansWasCalled = false;
+
+ // -- Test typing in an opening tag symbol
+ mContent = new SpannableStringBuilder(initialText + "<");
+
+ mWatcher.onTextChanged(mContent, offset, 0, 1);
+ mWatcher.afterTextChanged(mContent);
+
+ // No formatting should be applied/removed
+ assertEquals(false, mUpdateSpansWasCalled);
+
+
+ // -- Test typing in the closing tag slash
+ mContent = new SpannableStringBuilder(initialText + "</");
+
+ mWatcher.onTextChanged(mContent, offset + 1, 0, 1);
+ mWatcher.afterTextChanged(mContent);
+
+ // No formatting should be applied/removed
+ assertEquals(false, mUpdateSpansWasCalled);
+
+ // -- Test typing in the tag name
+ mContent = new SpannableStringBuilder(initialText + "</b");
+
+ mWatcher.onTextChanged(mContent, offset + 2, 0, 1);
+ mWatcher.afterTextChanged(mContent);
+
+ // No formatting should be applied/removed
+ assertEquals(false, mUpdateSpansWasCalled);
+
+
+ // -- Test typing in a closing tag symbol
+ mContent = new SpannableStringBuilder(initialText + "</b>");
+
+ mWatcher.onTextChanged(mContent, offset + 3, 0, 1);
+ mWatcher.afterTextChanged(mContent);
+
+ assertEquals(offset, mSpanRange.getOpeningTagLoc());
+ assertEquals(offset + 4, mSpanRange.getClosingTagLoc());
+ }
+ }
+
+ @Test
+ public void testTypingInTagWithSurroundingTags() {
+ // Spans in this case will be applied until the end of the next tag
+ // This fixes a pasting bug and might be refined later
+ // -- Test typing in the opening tag symbol
+ mContent = new SpannableStringBuilder("some <del>text</del> < <b>bold text</b>");
+
+ mWatcher.onTextChanged(mContent, 21, 0, 1); // Added lone "<"
+ mWatcher.afterTextChanged(mContent);
+
+ assertEquals(21, mSpanRange.getOpeningTagLoc());
+ assertEquals(26, mSpanRange.getClosingTagLoc());
+
+
+ // -- Test typing in the tag name
+ mContent = new SpannableStringBuilder("some <del>text</del> <i <b>bold text</b>");
+
+ mWatcher.onTextChanged(mContent, 22, 0, 1);
+ mWatcher.afterTextChanged(mContent);
+
+ assertEquals(21, mSpanRange.getOpeningTagLoc());
+ assertEquals(27, mSpanRange.getClosingTagLoc());
+
+
+ // -- Test typing in the closing tag symbol
+ mContent = new SpannableStringBuilder("some <del>text</del> <i> <b>bold text</b>");
+
+ mWatcher.onTextChanged(mContent, 23, 0, 1);
+ mWatcher.afterTextChanged(mContent);
+
+ assertEquals(21, mSpanRange.getOpeningTagLoc());
+ assertEquals(28, mSpanRange.getClosingTagLoc());
+ }
+
+ @Test
+ public void testTypingInLoneClosingSymbol() {
+ // -- Test typing in an isolated closing tag symbol
+ mContent = new SpannableStringBuilder("some text >");
+
+ mWatcher.onTextChanged(mContent, 10, 0, 1);
+ mWatcher.afterTextChanged(mContent);
+
+ // No formatting should be applied/removed
+ assertEquals(false, mUpdateSpansWasCalled);
+
+
+ // -- Test typing in an isolated closing tag symbol with surrounding tags
+ mContent = new SpannableStringBuilder("some <b>tex>t</b>");
+
+ mWatcher.onTextChanged(mContent, 11, 0, 1); // Added lone ">"
+ mWatcher.afterTextChanged(mContent);
+
+ // The span in this case will be applied from the start of the previous tag to the end of the next tag
+ assertEquals(5, mSpanRange.getOpeningTagLoc());
+ assertEquals(17, mSpanRange.getClosingTagLoc());
+ }
+
+ @Test
+ public void testTypingInEntity() {
+ // Test with several different cases of pre-existing text
+ String[] previousTextCases = new String[]{"", "plain text", "&rho;",
+ "<blockquote>some existing content &dagger;</blockquote> "};
+ for (String initialText : previousTextCases) {
+ int offset = initialText.length();
+ mUpdateSpansWasCalled = false;
+
+ // -- Test typing in the entity's opening '&'
+ mContent = new SpannableStringBuilder(initialText + "&");
+
+ mWatcher.onTextChanged(mContent, offset, 0, 1);
+ mWatcher.afterTextChanged(mContent);
+
+ // No formatting should be applied/removed
+ assertEquals(false, mUpdateSpansWasCalled);
+
+
+ // -- Test typing in the entity's main text
+ mContent = new SpannableStringBuilder(initialText + "&amp");
+
+ mWatcher.onTextChanged(mContent, offset + 3, 0, 1);
+ mWatcher.afterTextChanged(mContent);
+
+ // No formatting should be applied/removed
+ assertEquals(false, mUpdateSpansWasCalled);
+
+
+ // -- Test typing in the entity's closing ';'
+ mContent = new SpannableStringBuilder(initialText + "&amp;");
+
+ mWatcher.onTextChanged(mContent, offset + 4, 0, 1);
+ mWatcher.afterTextChanged(mContent);
+
+ assertEquals(offset, mSpanRange.getOpeningTagLoc());
+ assertEquals(offset + 5, mSpanRange.getClosingTagLoc());
+ }
+ }
+
+ @Test
+ public void testAddingTagFromFormatBar() {
+ // -- Test adding a tag to an empty document
+ mContent = new SpannableStringBuilder("<b>");
+
+ mWatcher.onTextChanged(mContent, 0, 0, 3);
+ mWatcher.afterTextChanged(mContent);
+
+ assertEquals(0, mSpanRange.getOpeningTagLoc());
+ assertEquals(3, mSpanRange.getClosingTagLoc());
+
+
+ // -- Test adding a tag at the end of a document with text
+ mContent = new SpannableStringBuilder("stuff<b>");
+
+ mWatcher.onTextChanged(mContent, 5, 0, 3);
+ mWatcher.afterTextChanged(mContent);
+
+ assertEquals(5, mSpanRange.getOpeningTagLoc());
+ assertEquals(8, mSpanRange.getClosingTagLoc());
+
+
+ // -- Test adding a tag at the end of a document containing other html
+ mContent = new SpannableStringBuilder("some text <i>italics</i> <b>");
+
+ mWatcher.onTextChanged(mContent, 25, 0, 3); // Added "<b>"
+ mWatcher.afterTextChanged(mContent);
+
+ assertEquals(25, mSpanRange.getOpeningTagLoc());
+ assertEquals(28, mSpanRange.getClosingTagLoc());
+
+
+ // -- Test adding a tag at the start of a document with text
+ mContent = new SpannableStringBuilder("<b>some text");
+
+ mWatcher.onTextChanged(mContent, 0, 0, 3);
+ mWatcher.afterTextChanged(mContent);
+
+ assertEquals(0, mSpanRange.getOpeningTagLoc());
+ assertEquals(3, mSpanRange.getClosingTagLoc());
+
+
+ // -- Test adding a tag at the start of a document containing other html
+ mContent = new SpannableStringBuilder("<b>some text <i>italics</i>");
+
+ mWatcher.onTextChanged(mContent, 0, 0, 3);
+ mWatcher.afterTextChanged(mContent);
+
+ assertEquals(0, mSpanRange.getOpeningTagLoc());
+ assertEquals(3, mSpanRange.getClosingTagLoc());
+
+
+ // -- Test adding a tag within another tag pair
+ mContent = new SpannableStringBuilder("<b>some <i>text</b>");
+
+ mWatcher.onTextChanged(mContent, 8, 0, 3); // Added <i>
+ mWatcher.afterTextChanged(mContent);
+
+ assertEquals(8, mSpanRange.getOpeningTagLoc());
+ assertEquals(11, mSpanRange.getClosingTagLoc());
+
+
+ // -- Test adding a closing tag within another tag pair
+ mContent = new SpannableStringBuilder("<b>some <i>text</i></b>");
+
+ mWatcher.onTextChanged(mContent, 15, 0, 4); // Added "</i>"
+ mWatcher.afterTextChanged(mContent);
+
+ assertEquals(15, mSpanRange.getOpeningTagLoc());
+ assertEquals(19, mSpanRange.getClosingTagLoc());
+ }
+
+ @Test
+ public void testAddingListTagsFromFormatBar() {
+ // -- Test adding a list tag to an empty document
+ mContent = new SpannableStringBuilder("<ul>\n\t<li>");
+
+ mWatcher.onTextChanged(mContent, 0, 0, 10);
+ mWatcher.afterTextChanged(mContent);
+
+ assertEquals(0, mSpanRange.getOpeningTagLoc());
+ assertEquals(10, mSpanRange.getClosingTagLoc());
+
+
+ // -- Test adding a closing list tag
+ mContent = new SpannableStringBuilder("<ul>\n" + //5
+ "\t<li>list item</li>\n" + //20
+ "\t<li>another list item</li>\n" + //22
+ "</ul>");
+
+ mWatcher.onTextChanged(mContent, 47, 0, 11); // Added "</li>\n</ul>"
+ mWatcher.afterTextChanged(mContent);
+
+ assertEquals(47, mSpanRange.getOpeningTagLoc());
+ assertEquals(58, mSpanRange.getClosingTagLoc());
+ }
+
+ @Test
+ public void testDeletingPartsOfTag() {
+ // -- Test deleting different characters within a tag
+ mContent = new SpannableStringBuilder("<b>stuff</b>");
+
+ int deletedChar = 0;
+ mWatcher.beforeTextChanged(mContent, deletedChar, 1, 0);
+ // Deleted characters are removed from the string between beforeTextChanged() and onTextChanged()
+ mContent.delete(deletedChar, deletedChar + 1);
+ mWatcher.onTextChanged(mContent, deletedChar, 1, 0);
+ mWatcher.afterTextChanged(mContent);
+
+ // "b>" should be re-styled
+ assertEquals(0, mSpanRange.getOpeningTagLoc());
+ assertEquals(2, mSpanRange.getClosingTagLoc());
+
+ for (int i = 8; i < 12; i++) {
+ mContent = new SpannableStringBuilder("<b>stuff</b>");
+
+ mWatcher.beforeTextChanged(mContent, i, 1, 0);
+ mContent.delete(i, i + 1);
+ mWatcher.afterTextChanged(mContent);
+
+ // Style should be updated starting from the end of 'stuff'
+ assertEquals(8, mSpanRange.getOpeningTagLoc());
+ assertEquals(mContent.length(), mSpanRange.getClosingTagLoc());
+ }
+ }
+
+ @Test
+ public void testPasteTagPair() {
+ // -- Test pasting in a set of opening and closing tags at the end of the document
+ mContent = new SpannableStringBuilder("text <b></b>");
+
+ mWatcher.onTextChanged(mContent, 5, 0, 7);
+ mWatcher.afterTextChanged(mContent);
+
+ assertEquals(5, mSpanRange.getOpeningTagLoc());
+ assertEquals(12, mSpanRange.getClosingTagLoc());
+ }
+
+ @Test
+ public void testCutAndPasteTagPart() {
+ // -- Test cutting a tag and part of another tag from the document
+ mContent = new SpannableStringBuilder("test <b></b> <i>italics</i>");
+
+ mWatcher.beforeTextChanged(mContent, 5, 4, 0); // Deleted "<b><"
+ mContent.delete(5, 9);
+ mWatcher.onTextChanged(mContent, 5, 4, 0);
+ mWatcher.afterTextChanged(mContent);
+
+ assertEquals(5, mSpanRange.getOpeningTagLoc());
+ assertEquals(8, mSpanRange.getClosingTagLoc());
+
+
+ // -- Test pasting the cut text back in
+ mContent = new SpannableStringBuilder("test <b></b> <i>italics</i>");
+ mWatcher.onTextChanged(mContent, 5, 0, 4); // Pasted "<b><" back in
+ mWatcher.afterTextChanged(mContent);
+
+ assertEquals(5, mSpanRange.getOpeningTagLoc());
+ assertEquals(12, mSpanRange.getClosingTagLoc());
+ }
+
+ @Test
+ public void testCutAndPasteTagPartReplacingText() {
+ // -- Test pasting cut text while text is selected
+ // Pasted "<b><", replacing "st " of "test "
+ mContent = new SpannableStringBuilder("test /b> <i>italics</i>");
+ mWatcher.beforeTextChanged(mContent, 2, 3, 4);
+ mContent = new SpannableStringBuilder("te<b></b> <i>italics</i>");
+ mWatcher.onTextChanged(mContent, 2, 3, 4);
+ mWatcher.afterTextChanged(mContent);
+
+ // Should re-style whole document
+ assertEquals(0, mSpanRange.getOpeningTagLoc());
+ assertEquals(mContent.length(), mSpanRange.getClosingTagLoc());
+
+
+ // -- Test pasting cut text while text is selected, case 2
+ // Pasted "i>", replacing "test "
+ mContent = new SpannableStringBuilder("<test italics</i>");
+ mWatcher.beforeTextChanged(mContent, 1, 5, 2);
+ mContent = new SpannableStringBuilder("<i>italics</i>");
+ mWatcher.onTextChanged(mContent, 1, 5, 2);
+ mWatcher.afterTextChanged(mContent);
+
+ // Should re-style whole document
+ assertEquals(0, mSpanRange.getOpeningTagLoc());
+ assertEquals(mContent.length(), mSpanRange.getClosingTagLoc());
+ }
+
+ @Test
+ public void testNoChange() {
+
+ mWatcher.beforeTextChanged("sample", 0, 0, 0);
+ mWatcher.onTextChanged("sample", 0, 0, 0);
+ mWatcher.afterTextChanged(null);
+
+ // No formatting should be applied/removed
+ assertEquals(false, mUpdateSpansWasCalled);
+ }
+
+ @Test
+ public void testUpdateSpans() {
+ // -- Test tag styling
+ HtmlStyleTextWatcher watcher = new HtmlStyleTextWatcher();
+ Spannable content = new SpannableStringBuilder("<b>stuff</b>");
+ watcher.updateSpans(content, new HtmlStyleTextWatcher.SpanRange(0, 3));
+
+ assertEquals(1, content.getSpans(0, 3, ForegroundColorSpan.class).length);
+
+ // -- Test entity styling
+ content = new SpannableStringBuilder("text &amp; more text");
+ watcher.updateSpans(content, new HtmlStyleTextWatcher.SpanRange(5, 10));
+
+ assertEquals(1, content.getSpans(5, 10, ForegroundColorSpan.class).length);
+ assertEquals(1, content.getSpans(5, 10, StyleSpan.class).length);
+ assertEquals(1, content.getSpans(5, 10, RelativeSizeSpan.class).length);
+
+ // -- Test comment styling
+ content = new SpannableStringBuilder("text <!--comment--> more text");
+ watcher.updateSpans(content, new HtmlStyleTextWatcher.SpanRange(5, 19));
+
+ assertEquals(1, content.getSpans(5, 19, ForegroundColorSpan.class).length);
+ assertEquals(1, content.getSpans(5, 19, StyleSpan.class).length);
+ assertEquals(1, content.getSpans(5, 19, RelativeSizeSpan.class).length);
+
+ content = new SpannableStringBuilder("<b>stuff</b>");
+ watcher.updateSpans(content, new HtmlStyleTextWatcher.SpanRange(0, 3));
+
+ watcher.updateSpans(content, new HtmlStyleTextWatcher.SpanRange(0, 42));
+ assertEquals(1, content.getSpans(0, 3, ForegroundColorSpan.class).length);
+
+ }
+
+ private class HtmlStyleTextWatcherForTests extends HtmlStyleTextWatcher {
+ @Override
+ protected void updateSpans(Spannable s, SpanRange spanRange) {
+ mSpanRange = spanRange;
+ mUpdateSpansWasCalled = true;
+ }
+ }
+}