package com.nokia.mid.ui; import gnu.testlet.TestHarness; import gnu.testlet.Testlet; import gnu.testlet.TestUtils; import javax.microedition.lcdui.Alert; import javax.microedition.lcdui.Canvas; import javax.microedition.lcdui.Display; import javax.microedition.lcdui.Font; import javax.microedition.lcdui.Graphics; import javax.microedition.lcdui.TextField; public class TestTextEditor extends Canvas implements Testlet { public int getExpectedPass() { return 146; } public int getExpectedFail() { return 0; } public int getExpectedKnownFail() { return 0; } public void testConstraints(TestHarness th, int constraints, int tolerance) { String text = "</div>Hello, world!"; TextEditor textEditor = new TextEditor(text, 20, 0, 100, 24); textEditor.setVisible(true); th.check(textEditor.getContent(), text); th.check(textEditor.getMaxSize(), 20); th.check(textEditor.getCaretPosition(), text.length()); textEditor.setConstraints(constraints); th.check(textEditor.getConstraints(), constraints); th.check(textEditor.getWidth(), 100); th.check(textEditor.getHeight(), 24); textEditor.setContent("Helló, világ!"); th.check(textEditor.getContent(), "Helló, világ!"); th.check(textEditor.setMaxSize(22), 22); th.check(textEditor.getMaxSize(), 22); th.check(textEditor.getContent(), "Helló, világ!"); th.check(textEditor.setMaxSize(5), 5); th.check(textEditor.getContent(), "Helló"); th.check(textEditor.getCaretPosition(), 5); textEditor.delete(2, 2); th.check(textEditor.getContent(), "Heó"); th.check(textEditor.getCaretPosition(), 2); textEditor.insert("ll", 2); th.check(textEditor.getContent(), "Helló"); th.check(textEditor.getCaretPosition(), 4); textEditor.setSize(120, 28); th.check(textEditor.getWidth(), 120); th.check(textEditor.getHeight(), 28); th.check(textEditor.isVisible(), true); textEditor.setVisible(false); th.check(textEditor.isVisible(), false); textEditor.setVisible(true); th.check(textEditor.isVisible(), true); textEditor.setParent(this); th.check(textEditor.getParent(), this); th.check(textEditor.isMultiline(), false); textEditor.setMultiline(true); th.check(textEditor.isMultiline(), true); textEditor.setMultiline(false); th.check(textEditor.isMultiline(), false); th.check(textEditor.getBackgroundColor(), 0xFFFFFFFF); textEditor.setBackgroundColor(0xBBBBBBBB); th.check(textEditor.getBackgroundColor(), 0xBBBBBBBB); th.check(textEditor.getForegroundColor(), 0xFF000000); textEditor.setForegroundColor(0x33333333); th.check(textEditor.getForegroundColor(), 0x33333333); th.check(textEditor.getLineMarginHeight(), 0); int value = Math.abs(textEditor.getContentHeight() - Font.getDefaultFont().getHeight()); th.check(value <= tolerance, "One: " + value); textEditor.setMultiline(true); value = Math.abs(textEditor.getContentHeight() - Font.getDefaultFont().getHeight()); th.check(value <= tolerance, "Two: " + value); textEditor.setContent("A\nB"); value = Math.abs(textEditor.getContentHeight() - Font.getDefaultFont().getHeight() * 2); th.check(value <= tolerance * 2, "Three: " + value); textEditor.setContent("A\r\nB"); value = Math.abs(textEditor.getContentHeight() - Font.getDefaultFont().getHeight() * 2); th.check(value <= tolerance * 2, "Four: " + value); textEditor.setContent("A\nB\nC"); value = Math.abs(textEditor.getContentHeight() - Font.getDefaultFont().getHeight() * 3); th.check(value <= tolerance * 3, "Five: " + value); textEditor.setContent(""); value = Math.abs(textEditor.getContentHeight() - Font.getDefaultFont().getHeight()); th.check(value <= tolerance, "Six: " + value); th.check(textEditor.getPositionX(), 0); th.check(textEditor.getPositionY(), 0); textEditor.setPosition(10, 20); th.check(textEditor.getPositionX(), 10); th.check(textEditor.getPositionY(), 20); textEditor.setPosition(-10, -20); th.check(textEditor.getPositionX(), -10); th.check(textEditor.getPositionY(), -20); textEditor.setVisible(true); textEditor.setContent("XYZYZ"); th.check(textEditor.getCaretPosition(), 5); textEditor.setCaret(3); th.check(textEditor.getCaretPosition(), 3); textEditor.setCaret(5); th.check(textEditor.getCaretPosition(), 5); textEditor.setCaret(0); th.check(textEditor.getCaretPosition(), 0); try { textEditor.setCaret(-1); th.fail("Exception expected"); } catch (StringIndexOutOfBoundsException e) { th.check(true, "Exception expected"); } th.check(textEditor.getCaretPosition(), 0); try { textEditor.setCaret(6); th.fail("Exception expected"); } catch (StringIndexOutOfBoundsException e) { th.check(true, "Exception expected"); } th.check(textEditor.getCaretPosition(), 0); Font font = Font.getFont(Font.FACE_SYSTEM, Font.STYLE_PLAIN, Font.SIZE_LARGE); textEditor.setFont(font); th.check(textEditor.getFont(), font); textEditor.setVisible(false); textEditor.setParent(null); } public void testEmoji(TestHarness th) { TextEditor textEditor = TextEditor.createTextEditor("Hello, world!", 200, TextField.ANY, 150, 50); textEditor.setParent(this); textEditor.setMultiline(true); textEditor.setBackgroundColor(0x00FFFFFF); textEditor.setForegroundColor(0xFF000000); textEditor.setVisible(true); textEditor.setPosition(0, 0); th.check(textEditor.getCaretPosition(), 13); String code = TestUtils.getEmojiString("1f609"); textEditor.insert(code, textEditor.getCaretPosition()); th.check(textEditor.getCaretPosition(), 14); textEditor.insert(code, textEditor.getCaretPosition()); th.check(textEditor.getCaretPosition(), 15); th.check(textEditor.size(), 15); textEditor.insert(code, 0); th.check(textEditor.getCaretPosition(), 1); th.check(textEditor.size(), 16); textEditor.insert(code, 1); th.check(textEditor.getCaretPosition(), 2); th.check(textEditor.size(), 17); textEditor.delete(1, 1); th.check(textEditor.size(), 16); // Emoji + "Hello, world!" + Emoji + Emoji th.check(textEditor.getContent(), code + "Hello, world!" + code + code); // Set caret position at the beginning textEditor.setCaret(0); th.check(textEditor.getCaretPosition(), 0); // Set caret position after the first emoji textEditor.setCaret(1); th.check(textEditor.getCaretPosition(), 1); // Set caret position in the middle of the text textEditor.setCaret(7); th.check(textEditor.getCaretPosition(), 7); // Set caret position before an emoji textEditor.setCaret(14); th.check(textEditor.getCaretPosition(), 14); // Set caret position between two emojis textEditor.setCaret(15); th.check(textEditor.getCaretPosition(), 15); // Set caret position at the end textEditor.setCaret(16); th.check(textEditor.getCaretPosition(), 16); try { textEditor.setCaret(17); th.fail("Exception expected"); } catch (StringIndexOutOfBoundsException e) { th.check(true, "Exception expected"); } // Test with empty TextEditor textEditor.setContent(""); th.check(textEditor.getContent(), ""); th.check(textEditor.getCaretPosition(), 0); // Test with a blank line textEditor.setContent("\n"); th.check(textEditor.size(), 1); th.check(textEditor.getCaretPosition(), 1); textEditor.setCaret(0); th.check(textEditor.getCaretPosition(), 0); textEditor.setCaret(1); th.check(textEditor.getCaretPosition(), 1); // Test setting caret position to 0 with text textEditor.setContent("Ciao"); textEditor.setCaret(0); th.check(textEditor.getCaretPosition(), 0); // An emoji with 2 codepoints turns into another emoji with 1 codepoint if // you press backspace (or call delete on one of the codepoints). // This looks weird to me, but it's how the Nokia implementation works. // Also, the size() and the getCaretPosition() methods return a number // related to the number of codepoints present, not the number of emoji. // So, in theory, you could set the caret position in the middle of an emoji. // Even if we don't want to do this when the user presses backspace (and indeed // we aren't doing it), we still want to keep the behavior of the API compatible // to the Nokia one. So we allow setting the caret position in the middle of an // emoji, we allow removing one of the two codepoints with the |delete| method and // we consider one emoji with two codepoints as taking two spaces in the TextEditor. // Hence, we're testing this behavior here. textEditor.setContent(TestUtils.getEmojiString("1f1ee1f1f9")); th.check(textEditor.getCaretPosition(), 2); th.check(textEditor.size(), 2); textEditor.delete(1, 1); th.check(textEditor.getContent(), TestUtils.getEmojiString("1f1ee")); th.check(textEditor.getCaretPosition(), 1); th.check(textEditor.size(), 1); textEditor.setContent(TestUtils.getEmojiString("1f1ee1f1f9")); textEditor.delete(0, 1); th.check(textEditor.getContent(), TestUtils.getEmojiString("1f1f9")); th.check(textEditor.getCaretPosition(), 0); th.check(textEditor.size(), 1); textEditor.setContent(TestUtils.getEmojiString("2320e3")); th.check(textEditor.getCaretPosition(), 2); th.check(textEditor.size(), 2); textEditor.delete(1, 1); th.check(textEditor.getContent(), "#"); th.check(textEditor.getCaretPosition(), 1); th.check(textEditor.size(), 1); textEditor.setContent(TestUtils.getEmojiString("2320e3")); textEditor.delete(0, 1); th.check(textEditor.getContent(), TestUtils.getEmojiString("20e3")); th.check(textEditor.getCaretPosition(), 0); th.check(textEditor.size(), 1); // Test setting maxSize with emoji textEditor.setContent(code + code + code); textEditor.setMaxSize(2); th.check(textEditor.size(), 2); th.check(textEditor.getCaretPosition(), 2); textEditor.setVisible(false); } public void test(TestHarness th) { testConstraints(th, TextField.ANY, 5); testConstraints(th, TextField.PASSWORD, 0); testEmoji(th); } protected void paint(Graphics graphics) {} }