Split up into modules and add float module

Split the app/ module into three modules

terminal/ - Terminal emulator library module.
view/ - Terminal view library module (depending on terminal/).
app/ - The main Termux app (depending on view/).

Also add the

float/ - The Termux:Float app (depending on view/).
This commit is contained in:
Fredrik Fornwall
2017-04-01 19:06:02 +02:00
parent 41d0d60017
commit 009de5a3ee
82 changed files with 968 additions and 39 deletions

View File

@@ -1,54 +0,0 @@
package com.termux.terminal;
import junit.framework.TestCase;
public class ByteQueueTest extends TestCase {
private static void assertArrayEquals(byte[] expected, byte[] actual) {
if (expected.length != actual.length) {
fail("Difference array length");
}
for (int i = 0; i < expected.length; i++) {
if (expected[i] != actual[i]) {
fail("Inequals at index=" + i + ", expected=" + (int) expected[i] + ", actual=" + (int) actual[i]);
}
}
}
public void testCompleteWrites() throws Exception {
ByteQueue q = new ByteQueue(10);
assertEquals(true, q.write(new byte[]{1, 2, 3}, 0, 3));
byte[] arr = new byte[10];
assertEquals(3, q.read(arr, true));
assertArrayEquals(new byte[]{1, 2, 3}, new byte[]{arr[0], arr[1], arr[2]});
assertEquals(true, q.write(new byte[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, 0, 10));
assertEquals(10, q.read(arr, true));
assertArrayEquals(new byte[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, arr);
}
public void testQueueWraparound() throws Exception {
ByteQueue q = new ByteQueue(10);
byte[] origArray = new byte[]{1, 2, 3, 4, 5, 6};
byte[] readArray = new byte[origArray.length];
for (int i = 0; i < 20; i++) {
q.write(origArray, 0, origArray.length);
assertEquals(origArray.length, q.read(readArray, true));
assertArrayEquals(origArray, readArray);
}
}
public void testWriteNotesClosing() throws Exception {
ByteQueue q = new ByteQueue(10);
q.close();
assertEquals(false, q.write(new byte[]{1, 2, 3}, 0, 3));
}
public void testReadNonBlocking() throws Exception {
ByteQueue q = new ByteQueue(10);
assertEquals(0, q.read(new byte[128], false));
}
}

View File

@@ -1,32 +0,0 @@
package com.termux.terminal;
/** "\033[" is the Control Sequence Introducer char sequence (CSI). */
public class ControlSequenceIntroducerTest extends TerminalTestCase {
/** CSI Ps P Scroll down Ps lines (default = 1) (SD). */
public void testCsiT() {
withTerminalSized(4, 6).enterString("1\r\n2\r\n3\r\nhi\033[2Tyo\r\nA\r\nB").assertLinesAre(" ", " ", "1 ", "2 yo", "A ",
"Bi ");
// Default value (1):
withTerminalSized(4, 6).enterString("1\r\n2\r\n3\r\nhi\033[Tyo\r\nA\r\nB").assertLinesAre(" ", "1 ", "2 ", "3 yo", "Ai ",
"B ");
}
/** CSI Ps S Scroll up Ps lines (default = 1) (SU). */
public void testCsiS() {
// The behaviour here is a bit inconsistent between terminals - this is how the OS X Terminal.app does it:
withTerminalSized(3, 4).enterString("1\r\n2\r\n3\r\nhi\033[2Sy").assertLinesAre("3 ", "hi ", " ", " y");
// Default value (1):
withTerminalSized(3, 4).enterString("1\r\n2\r\n3\r\nhi\033[Sy").assertLinesAre("2 ", "3 ", "hi ", " y");
}
/** CSI Ps X Erase Ps Character(s) (default = 1) (ECH). */
public void testCsiX() {
// See https://code.google.com/p/chromium/issues/detail?id=212712 where test was extraced from.
withTerminalSized(13, 2).enterString("abcdefghijkl\b\b\b\b\b\033[X").assertLinesAre("abcdefg ijkl ", " ");
withTerminalSized(13, 2).enterString("abcdefghijkl\b\b\b\b\b\033[1X").assertLinesAre("abcdefg ijkl ", " ");
withTerminalSized(13, 2).enterString("abcdefghijkl\b\b\b\b\b\033[2X").assertLinesAre("abcdefg jkl ", " ");
withTerminalSized(13, 2).enterString("abcdefghijkl\b\b\b\b\b\033[20X").assertLinesAre("abcdefg ", " ");
}
}

View File

@@ -1,230 +0,0 @@
package com.termux.terminal;
import junit.framework.Assert;
public class CursorAndScreenTest extends TerminalTestCase {
public void testDeleteLinesKeepsStyles() {
int cols = 5, rows = 5;
withTerminalSized(cols, rows);
for (int row = 0; row < 5; row++) {
for (int col = 0; col < 5; col++) {
// Foreground color to col, background to row:
enterString("\033[38;5;" + col + "m");
enterString("\033[48;5;" + row + "m");
enterString(Character.toString((char) ('A' + col + row * 5)));
}
}
assertLinesAre("ABCDE", "FGHIJ", "KLMNO", "PQRST", "UVWXY");
for (int row = 0; row < 5; row++) {
for (int col = 0; col < 5; col++) {
long s = getStyleAt(row, col);
Assert.assertEquals(col, TextStyle.decodeForeColor(s));
Assert.assertEquals(row, TextStyle.decodeBackColor(s));
}
}
// "${CSI}H" - place cursor at 1,1, then "${CSI}2M" to delete two lines.
enterString("\033[H\033[2M");
assertLinesAre("KLMNO", "PQRST", "UVWXY", " ", " ");
for (int row = 0; row < 3; row++) {
for (int col = 0; col < 5; col++) {
long s = getStyleAt(row, col);
Assert.assertEquals(col, TextStyle.decodeForeColor(s));
Assert.assertEquals(row + 2, TextStyle.decodeBackColor(s));
}
}
// Set default fg and background for the new blank lines:
enterString("\033[38;5;98m");
enterString("\033[48;5;99m");
// "${CSI}B" to go down one line, then "${CSI}2L" to insert two lines:
enterString("\033[B\033[2L");
assertLinesAre("KLMNO", " ", " ", "PQRST", "UVWXY");
for (int row = 0; row < 5; row++) {
for (int col = 0; col < 5; col++) {
int wantedForeground = (row == 1 || row == 2) ? 98 : col;
int wantedBackground = (row == 1 || row == 2) ? 99 : (row == 0 ? 2 : row);
long s = getStyleAt(row, col);
Assert.assertEquals(wantedForeground, TextStyle.decodeForeColor(s));
Assert.assertEquals(wantedBackground, TextStyle.decodeBackColor(s));
}
}
}
public void testDeleteCharacters() {
withTerminalSized(5, 2).enterString("枝ce").assertLinesAre("枝ce ", " ");
withTerminalSized(5, 2).enterString("a枝ce").assertLinesAre("a枝ce", " ");
withTerminalSized(5, 2).enterString("nice").enterString("\033[G\033[P").assertLinesAre("ice ", " ");
withTerminalSized(5, 2).enterString("nice").enterString("\033[G\033[2P").assertLinesAre("ce ", " ");
withTerminalSized(5, 2).enterString("nice").enterString("\033[2G\033[2P").assertLinesAre("ne ", " ");
// "${CSI}${n}P, the delete characters (DCH) sequence should cap characters to delete.
withTerminalSized(5, 2).enterString("nice").enterString("\033[G\033[99P").assertLinesAre(" ", " ");
// With combining char U+0302.
withTerminalSized(5, 2).enterString("n\u0302ice").enterString("\033[G\033[2P").assertLinesAre("ce ", " ");
withTerminalSized(5, 2).enterString("n\u0302ice").enterString("\033[G\033[P").assertLinesAre("ice ", " ");
withTerminalSized(5, 2).enterString("n\u0302ice").enterString("\033[2G\033[2P").assertLinesAre("n\u0302e ", " ");
// With wide 枝 char, checking that putting char at part replaces other with whitespace:
withTerminalSized(5, 2).enterString("枝ce").enterString("\033[Ga").assertLinesAre("a ce ", " ");
withTerminalSized(5, 2).enterString("枝ce").enterString("\033[2Ga").assertLinesAre(" ace ", " ");
// With wide 枝 char, deleting either part replaces other with whitespace:
withTerminalSized(5, 2).enterString("枝ce").enterString("\033[G\033[P").assertLinesAre(" ce ", " ");
withTerminalSized(5, 2).enterString("枝ce").enterString("\033[2G\033[P").assertLinesAre(" ce ", " ");
withTerminalSized(5, 2).enterString("枝ce").enterString("\033[2G\033[2P").assertLinesAre(" e ", " ");
withTerminalSized(5, 2).enterString("枝ce").enterString("\033[G\033[2P").assertLinesAre("ce ", " ");
withTerminalSized(5, 2).enterString("a枝ce").enterString("\033[G\033[P").assertLinesAre("枝ce ", " ");
}
public void testInsertMode() {
// "${CSI}4h" enables insert mode.
withTerminalSized(5, 2).enterString("nice").enterString("\033[G\033[4hA").assertLinesAre("Anice", " ");
withTerminalSized(5, 2).enterString("nice").enterString("\033[2G\033[4hA").assertLinesAre("nAice", " ");
withTerminalSized(5, 2).enterString("nice").enterString("\033[G\033[4hABC").assertLinesAre("ABCni", " ");
// With combining char U+0302.
withTerminalSized(5, 2).enterString("n\u0302ice").enterString("\033[G\033[4hA").assertLinesAre("An\u0302ice", " ");
withTerminalSized(5, 2).enterString("n\u0302ice").enterString("\033[G\033[4hAB").assertLinesAre("ABn\u0302ic", " ");
withTerminalSized(5, 2).enterString("n\u0302ic\u0302e").enterString("\033[2G\033[4hA").assertLinesAre("n\u0302Aic\u0302e", " ");
// ... but without insert mode, combining char should be overwritten:
withTerminalSized(5, 2).enterString("n\u0302ice").enterString("\033[GA").assertLinesAre("Aice ", " ");
// ... also with two combining:
withTerminalSized(5, 2).enterString("n\u0302\u0302i\u0302ce").enterString("\033[GA").assertLinesAre("Ai\u0302ce ", " ");
// ... and in last column:
withTerminalSized(5, 2).enterString("n\u0302\u0302ice!\u0302").enterString("\033[5GA").assertLinesAre("n\u0302\u0302iceA", " ");
withTerminalSized(5, 2).enterString("nic\u0302e!\u0302").enterString("\033[4G枝").assertLinesAre("nic\u0302枝", " ");
withTerminalSized(5, 2).enterString("nic枝\u0302").enterString("\033[3GA").assertLinesAre("niA枝\u0302", " ");
withTerminalSized(5, 2).enterString("nic枝\u0302").enterString("\033[3GA").assertLinesAre("niA枝\u0302", " ");
// With wide 枝 char.
withTerminalSized(5, 2).enterString("nice").enterString("\033[G\033[4h枝").assertLinesAre("枝nic", " ");
withTerminalSized(5, 2).enterString("nice").enterString("\033[2G\033[4h枝").assertLinesAre("n枝ic", " ");
withTerminalSized(5, 2).enterString("n枝ce").enterString("\033[G\033[4ha").assertLinesAre("an枝c", " ");
}
/** HPA—Horizontal Position Absolute (http://www.vt100.net/docs/vt510-rm/HPA) */
public void testCursorHorizontalPositionAbsolute() {
withTerminalSized(4, 4).enterString("ABC\033[`").assertCursorAt(0, 0);
enterString("\033[1`").assertCursorAt(0, 0).enterString("\033[2`").assertCursorAt(0, 1);
enterString("\r\n\033[3`").assertCursorAt(1, 2).enterString("\033[22`").assertCursorAt(1, 3);
// Enable and configure right and left margins, first without origin mode:
enterString("\033[?69h\033[2;3s\033[`").assertCursorAt(0, 0).enterString("\033[22`").assertCursorAt(0, 3);
// .. now with origin mode:
enterString("\033[?6h\033[`").assertCursorAt(0, 1).enterString("\033[22`").assertCursorAt(0, 2);
}
public void testCursorForward() {
// "${CSI}${N:=1}C" moves cursor forward N columns:
withTerminalSized(6, 2).enterString("A\033[CB\033[2CC").assertLinesAre("A B C", " ");
// If an attempt is made to move the cursor to the right of the right margin, the cursor stops at the right margin:
withTerminalSized(6, 2).enterString("A\033[44CB").assertLinesAre("A B", " ");
// Enable right margin and verify that CUF ends at the set right margin:
withTerminalSized(6, 2).enterString("\033[?69h\033[1;3s\033[44CAB").assertLinesAre(" A ", "B ");
}
public void testCursorBack() {
// "${CSI}${N:=1}D" moves cursor back N columns:
withTerminalSized(3, 2).enterString("A\033[DB").assertLinesAre("B ", " ");
withTerminalSized(3, 2).enterString("AB\033[2DC").assertLinesAre("CB ", " ");
// If an attempt is made to move the cursor to the left of the left margin, the cursor stops at the left margin:
withTerminalSized(3, 2).enterString("AB\033[44DC").assertLinesAre("CB ", " ");
// Enable left margin and verify that CUB ends at the set left margin:
withTerminalSized(6, 2).enterString("ABCD\033[?69h\033[2;6s\033[44DE").assertLinesAre("AECD ", " ");
}
public void testCursorUp() {
// "${CSI}${N:=1}A" moves cursor up N rows:
withTerminalSized(3, 3).enterString("ABCDEFG\033[AH").assertLinesAre("ABC", "DHF", "G ");
withTerminalSized(3, 3).enterString("ABCDEFG\033[2AH").assertLinesAre("AHC", "DEF", "G ");
// If an attempt is made to move the cursor above the top margin, the cursor stops at the top margin:
withTerminalSized(3, 3).enterString("ABCDEFG\033[44AH").assertLinesAre("AHC", "DEF", "G ");
// Set top margin and validate that cursor does not go above it:
withTerminalSized(3, 3).enterString("\033[2rABCDEFG\033[44AH").assertLinesAre("ABC", "DHF", "G ");
}
public void testCursorDown() {
// "${CSI}${N:=1}B" moves cursor down N rows:
withTerminalSized(3, 3).enterString("AB\033[BC").assertLinesAre("AB ", " C", " ");
withTerminalSized(3, 3).enterString("AB\033[2BC").assertLinesAre("AB ", " ", " C");
// If an attempt is made to move the cursor below the bottom margin, the cursor stops at the bottom margin:
withTerminalSized(3, 3).enterString("AB\033[44BC").assertLinesAre("AB ", " ", " C");
// Set bottom margin and validate that cursor does not go above it:
withTerminalSized(3, 3).enterString("\033[1;2rAB\033[44BC").assertLinesAre("AB ", " C", " ");
}
public void testReportCursorPosition() {
withTerminalSized(10, 10);
for (int i = 0; i < 10; i++) {
for (int j = 0; j < 10; j++) {
enterString("\033[" + (i + 1) + ";" + (j + 1) + "H"); // CUP cursor position.
assertCursorAt(i, j);
// Device Status Report (DSR):
assertEnteringStringGivesResponse("\033[6n", "\033[" + (i + 1) + ";" + (j + 1) + "R");
// DECXCPR — Extended Cursor Position. Note that http://www.vt100.net/docs/vt510-rm/DECXCPR says
// the response is "${CSI}${LINE};${COLUMN};${PAGE}R" while xterm (http://invisible-island.net/xterm/ctlseqs/ctlseqs.html)
// drops the question mark. Expect xterm behaviour here.
assertEnteringStringGivesResponse("\033[?6n", "\033[?" + (i + 1) + ";" + (j + 1) + ";1R");
}
}
}
/**
* See comments on horizontal tab handling in TerminalEmulator.java.
*
* We do not want to color already written cells when tabbing over them.
*/
public void DISABLED_testHorizontalTabColorsBackground() {
withTerminalSized(10, 3).enterString("\033[48;5;15m").enterString("\t");
assertCursorAt(0, 8);
for (int i = 0; i < 10; i++) {
int expectedColor = i < 8 ? 15 : TextStyle.COLOR_INDEX_BACKGROUND;
assertEquals(expectedColor, TextStyle.decodeBackColor(getStyleAt(0, i)));
}
}
/**
* Test interactions between the cursor overflow bit and various escape sequences.
* <p/>
* Adapted from hterm:
* https://chromium.googlesource.com/chromiumos/platform/assets/+/2337afa5c063127d5ce40ec7fec9b602d096df86%5E%21/#F2
*/
public void testClearingOfAutowrap() {
// Fill a row with the last hyphen wrong, then run a command that
// modifies the screen, then add a hyphen. The wrap bit should be
// cleared, so the extra hyphen can fix the row.
withTerminalSized(15, 6);
enterString("----- 1 ----X");
enterString("\033[K-"); // EL
enterString("----- 2 ----X");
enterString("\033[J-"); // ED
enterString("----- 3 ----X");
enterString("\033[@-"); // ICH
enterString("----- 4 ----X");
enterString("\033[P-"); // DCH
enterString("----- 5 ----X");
enterString("\033[X-"); // ECH
// DL will delete the entire line but clear the wrap bit, so we
// expect a hyphen at the end and nothing else.
enterString("XXXXXXXXXXXXXXX");
enterString("\033[M-"); // DL
assertLinesAre(
"----- 1 -----",
"----- 2 -----",
"----- 3 -----",
"----- 4 -----",
"----- 5 -----",
" -");
}
public void testBackspaceAcrossWrappedLines() {
// Backspace should not go to previous line if not auto-wrapped:
withTerminalSized(3, 3).enterString("hi\r\n\b\byou").assertLinesAre("hi ", "you", " ");
// Backspace should go to previous line if auto-wrapped:
withTerminalSized(3, 3).enterString("hi y").assertLinesAre("hi ", "y ", " ").enterString("\b\b#").assertLinesAre("hi#", "y ", " ");
// Initial backspace should do nothing:
withTerminalSized(3, 3).enterString("\b\b\b\bhi").assertLinesAre("hi ", " ", " ");
}
}

View File

@@ -1,78 +0,0 @@
package com.termux.terminal;
/**
* <pre>
* "CSI ? Pm h", DEC Private Mode Set (DECSET)
* </pre>
* <p/>
* and
* <p/>
* <pre>
* "CSI ? Pm l", DEC Private Mode Reset (DECRST)
* </pre>
* <p/>
* controls various aspects of the terminal
*/
public class DecSetTest extends TerminalTestCase {
/** DECSET 25, DECTCEM, controls visibility of the cursor. */
public void testShowHideCursor() {
withTerminalSized(3, 3);
assertTrue("Initially the cursor should be visible", mTerminal.isShowingCursor());
enterString("\033[?25l"); // Hide Cursor (DECTCEM).
assertFalse(mTerminal.isShowingCursor());
enterString("\033[?25h"); // Show Cursor (DECTCEM).
assertTrue(mTerminal.isShowingCursor());
enterString("\033[?25l"); // Hide Cursor (DECTCEM), again.
assertFalse(mTerminal.isShowingCursor());
mTerminal.reset();
assertTrue("Resetting the terminal should show the cursor", mTerminal.isShowingCursor());
enterString("\033[?25l");
assertFalse(mTerminal.isShowingCursor());
enterString("\033c"); // RIS resetting should reveal cursor.
assertTrue(mTerminal.isShowingCursor());
}
/** DECSET 2004, controls bracketed paste mode. */
public void testBracketedPasteMode() {
withTerminalSized(3, 3);
mTerminal.paste("a");
assertEquals("Pasting 'a' should output 'a' when bracketed paste mode is disabled", "a", mOutput.getOutputAndClear());
enterString("\033[?2004h"); // Enable bracketed paste mode.
mTerminal.paste("a");
assertEquals("Pasting when in bracketed paste mode should be bracketed", "\033[200~a\033[201~", mOutput.getOutputAndClear());
enterString("\033[?2004l"); // Disable bracketed paste mode.
mTerminal.paste("a");
assertEquals("Pasting 'a' should output 'a' when bracketed paste mode is disabled", "a", mOutput.getOutputAndClear());
enterString("\033[?2004h"); // Enable bracketed paste mode, again.
mTerminal.paste("a");
assertEquals("Pasting when in bracketed paste mode again should be bracketed", "\033[200~a\033[201~", mOutput.getOutputAndClear());
mTerminal.paste("\033ab\033cd\033");
assertEquals("Pasting an escape character should not input it", "\033[200~abcd\033[201~", mOutput.getOutputAndClear());
mTerminal.paste("\u0081ab\u0081cd\u009F");
assertEquals("Pasting C1 control codes should not input it", "\033[200~abcd\033[201~", mOutput.getOutputAndClear());
mTerminal.reset();
mTerminal.paste("a");
assertEquals("Terminal reset() should disable bracketed paste mode", "a", mOutput.getOutputAndClear());
}
/** DECSET 7, DECAWM, controls wraparound mode. */
public void testWrapAroundMode() {
// Default with wraparound:
withTerminalSized(3, 3).enterString("abcd").assertLinesAre("abc", "d ", " ");
// With wraparound disabled:
withTerminalSized(3, 3).enterString("\033[?7labcd").assertLinesAre("abd", " ", " ");
enterString("efg").assertLinesAre("abg", " ", " ");
// Re-enabling wraparound:
enterString("\033[?7hhij").assertLinesAre("abh", "ij ", " ");
}
}

View File

@@ -1,53 +0,0 @@
package com.termux.terminal;
/**
* "\033P" is a device control string.
*/
public class DeviceControlStringTest extends TerminalTestCase {
private static String hexEncode(String s) {
StringBuilder result = new StringBuilder();
for (int i = 0; i < s.length(); i++)
result.append(String.format("%02X", (int) s.charAt(i)));
return result.toString();
}
private void assertCapabilityResponse(String cap, String expectedResponse) {
String input = "\033P+q" + hexEncode(cap) + "\033\\";
assertEnteringStringGivesResponse(input, "\033P1+r" + hexEncode(cap) + "=" + hexEncode(expectedResponse) + "\033\\");
}
public void testReportColorsAndName() {
// Request Termcap/Terminfo String. The string following the "q" is a list of names encoded in
// hexadecimal (2 digits per character) separated by ; which correspond to termcap or terminfo key
// names.
// Two special features are also recognized, which are not key names: Co for termcap colors (or colors
// for terminfo colors), and TN for termcap name (or name for terminfo name).
// xterm responds with DCS 1 + r P t ST for valid requests, adding to P t an = , and the value of the
// corresponding string that xterm would send, or DCS 0 + r P t ST for invalid requests. The strings are
// encoded in hexadecimal (2 digits per character).
withTerminalSized(3, 3).enterString("A");
assertCapabilityResponse("Co", "256");
assertCapabilityResponse("colors", "256");
assertCapabilityResponse("TN", "xterm");
assertCapabilityResponse("name", "xterm");
enterString("B").assertLinesAre("AB ", " ", " ");
}
public void testReportKeys() {
withTerminalSized(3, 3);
assertCapabilityResponse("kB", "\033[Z");
}
public void testReallyLongDeviceControlString() {
withTerminalSized(3, 3).enterString("\033P");
for (int i = 0; i < 10000; i++) {
enterString("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa");
}
// The terminal should ignore the overlong DCS sequence and continue printing "aaa." and fill at least the first two lines with
// them:
assertLineIs(0, "aaa");
assertLineIs(1, "aaa");
}
}

View File

@@ -1,33 +0,0 @@
package com.termux.terminal;
public class HistoryTest extends TerminalTestCase {
public void testHistory() {
final int rows = 3;
final int cols = 3;
withTerminalSized(cols, rows).enterString("111222333444555666777888999");
assertCursorAt(2, 2);
assertLinesAre("777", "888", "999");
assertHistoryStartsWith("666", "555");
mTerminal.resize(cols, 2);
assertHistoryStartsWith("777", "666", "555");
mTerminal.resize(cols, 3);
assertHistoryStartsWith("666", "555");
}
public void testHistoryWithScrollRegion() {
// "CSI P_s ; P_s r" - set Scrolling Region [top;bottom] (default = full size of window) (DECSTBM).
withTerminalSized(3, 4).enterString("111222333444");
assertLinesAre("111", "222", "333", "444");
enterString("\033[2;3r");
// NOTE: "DECSTBM moves the cursor to column 1, line 1 of the page."
assertCursorAt(0, 0);
enterString("\nCDEFGH").assertLinesAre("111", "CDE", "FGH", "444");
enterString("IJK").assertLinesAre("111", "FGH", "IJK", "444").assertHistoryStartsWith("CDE");
enterString("LMN").assertLinesAre("111", "IJK", "LMN", "444").assertHistoryStartsWith("FGH", "CDE");
}
}

View File

@@ -1,191 +0,0 @@
package com.termux.terminal;
import android.view.KeyEvent;
import junit.framework.TestCase;
public class KeyHandlerTest extends TestCase {
private static String stringToHex(String s) {
if (s == null) return null;
StringBuilder buffer = new StringBuilder();
for (int i = 0; i < s.length(); i++) {
if (buffer.length() > 0) {
buffer.append(" ");
}
buffer.append("0x");
buffer.append(Integer.toHexString(s.charAt(i)));
}
return buffer.toString();
}
private static void assertKeysEquals(String expected, String actual) {
if (!expected.equals(actual)) {
assertEquals(stringToHex(expected), stringToHex(actual));
}
}
/** See http://pubs.opengroup.org/onlinepubs/7990989799/xcurses/terminfo.html */
public void testTermCaps() {
// Backspace.
assertKeysEquals("\u007f", KeyHandler.getCodeFromTermcap("kb", false, false));
// Back tab.
assertKeysEquals("\033[Z", KeyHandler.getCodeFromTermcap("kB", false, false));
// Arrow keys (up/down/right/left):
assertKeysEquals("\033[A", KeyHandler.getCodeFromTermcap("ku", false, false));
assertKeysEquals("\033[B", KeyHandler.getCodeFromTermcap("kd", false, false));
assertKeysEquals("\033[C", KeyHandler.getCodeFromTermcap("kr", false, false));
assertKeysEquals("\033[D", KeyHandler.getCodeFromTermcap("kl", false, false));
// .. shifted:
assertKeysEquals("\033[1;2A", KeyHandler.getCodeFromTermcap("kUP", false, false));
assertKeysEquals("\033[1;2B", KeyHandler.getCodeFromTermcap("kDN", false, false));
assertKeysEquals("\033[1;2C", KeyHandler.getCodeFromTermcap("%i", false, false));
assertKeysEquals("\033[1;2D", KeyHandler.getCodeFromTermcap("#4", false, false));
// Home/end keys:
assertKeysEquals("\033[H", KeyHandler.getCodeFromTermcap("kh", false, false));
assertKeysEquals("\033[F", KeyHandler.getCodeFromTermcap("@7", false, false));
// ... shifted:
assertKeysEquals("\033[1;2H", KeyHandler.getCodeFromTermcap("#2", false, false));
assertKeysEquals("\033[1;2F", KeyHandler.getCodeFromTermcap("*7", false, false));
// The traditional keyboard keypad:
// [Insert] [Home] [Page Up ]
// [Delete] [End] [Page Down]
//
// Termcap names (with xterm response in parenthesis):
// K1=Upper left of keypad (xterm sends same "<ESC>[H" = Home).
// K2=Center of keypad (xterm sends invalid response).
// K3=Upper right of keypad (xterm sends "<ESC>[5~" = Page Up).
// K4=Lower left of keypad (xterm sends "<ESC>[F" = End key).
// K5=Lower right of keypad (xterm sends "<ESC>[6~" = Page Down).
//
// vim/neovim (runtime/doc/term.txt):
// t_K1 <kHome> keypad home key
// t_K3 <kPageUp> keypad page-up key
// t_K4 <kEnd> keypad end key
// t_K5 <kPageDown> keypad page-down key
//
assertKeysEquals("\033[H", KeyHandler.getCodeFromTermcap("K1", false, false));
assertKeysEquals("\033OH", KeyHandler.getCodeFromTermcap("K1", true, false));
assertKeysEquals("\033[5~", KeyHandler.getCodeFromTermcap("K3", false, false));
assertKeysEquals("\033[F", KeyHandler.getCodeFromTermcap("K4", false, false));
assertKeysEquals("\033OF", KeyHandler.getCodeFromTermcap("K4", true, false));
assertKeysEquals("\033[6~", KeyHandler.getCodeFromTermcap("K5", false, false));
// Function keys F1-F12:
assertKeysEquals("\033OP", KeyHandler.getCodeFromTermcap("k1", false, false));
assertKeysEquals("\033OQ", KeyHandler.getCodeFromTermcap("k2", false, false));
assertKeysEquals("\033OR", KeyHandler.getCodeFromTermcap("k3", false, false));
assertKeysEquals("\033OS", KeyHandler.getCodeFromTermcap("k4", false, false));
assertKeysEquals("\033[15~", KeyHandler.getCodeFromTermcap("k5", false, false));
assertKeysEquals("\033[17~", KeyHandler.getCodeFromTermcap("k6", false, false));
assertKeysEquals("\033[18~", KeyHandler.getCodeFromTermcap("k7", false, false));
assertKeysEquals("\033[19~", KeyHandler.getCodeFromTermcap("k8", false, false));
assertKeysEquals("\033[20~", KeyHandler.getCodeFromTermcap("k9", false, false));
assertKeysEquals("\033[21~", KeyHandler.getCodeFromTermcap("k;", false, false));
assertKeysEquals("\033[23~", KeyHandler.getCodeFromTermcap("F1", false, false));
assertKeysEquals("\033[24~", KeyHandler.getCodeFromTermcap("F2", false, false));
// Function keys F13-F24 (same as shifted F1-F12):
assertKeysEquals("\033[1;2P", KeyHandler.getCodeFromTermcap("F3", false, false));
assertKeysEquals("\033[1;2Q", KeyHandler.getCodeFromTermcap("F4", false, false));
assertKeysEquals("\033[1;2R", KeyHandler.getCodeFromTermcap("F5", false, false));
assertKeysEquals("\033[1;2S", KeyHandler.getCodeFromTermcap("F6", false, false));
assertKeysEquals("\033[15;2~", KeyHandler.getCodeFromTermcap("F7", false, false));
assertKeysEquals("\033[17;2~", KeyHandler.getCodeFromTermcap("F8", false, false));
assertKeysEquals("\033[18;2~", KeyHandler.getCodeFromTermcap("F9", false, false));
assertKeysEquals("\033[19;2~", KeyHandler.getCodeFromTermcap("FA", false, false));
assertKeysEquals("\033[20;2~", KeyHandler.getCodeFromTermcap("FB", false, false));
assertKeysEquals("\033[21;2~", KeyHandler.getCodeFromTermcap("FC", false, false));
assertKeysEquals("\033[23;2~", KeyHandler.getCodeFromTermcap("FD", false, false));
assertKeysEquals("\033[24;2~", KeyHandler.getCodeFromTermcap("FE", false, false));
}
public void testKeyCodes() {
// Return sends carriage return (\r), which normally gets translated by the device driver to newline (\n) unless the ICRNL termios
// flag has been set.
assertKeysEquals("\r", KeyHandler.getCode(KeyEvent.KEYCODE_ENTER, 0, false, false));
// Backspace.
assertKeysEquals("\u007f", KeyHandler.getCode(KeyEvent.KEYCODE_DEL, 0, false, false));
// Space.
assertNull(KeyHandler.getCode(KeyEvent.KEYCODE_SPACE, 0, false, false));
assertKeysEquals("\u0000", KeyHandler.getCode(KeyEvent.KEYCODE_SPACE, KeyHandler.KEYMOD_CTRL, false, false));
// Back tab.
assertKeysEquals("\033[Z", KeyHandler.getCode(KeyEvent.KEYCODE_TAB, KeyHandler.KEYMOD_SHIFT, false, false));
// Arrow keys (up/down/right/left):
assertKeysEquals("\033[A", KeyHandler.getCode(KeyEvent.KEYCODE_DPAD_UP, 0, false, false));
assertKeysEquals("\033[B", KeyHandler.getCode(KeyEvent.KEYCODE_DPAD_DOWN, 0, false, false));
assertKeysEquals("\033[C", KeyHandler.getCode(KeyEvent.KEYCODE_DPAD_RIGHT, 0, false, false));
assertKeysEquals("\033[D", KeyHandler.getCode(KeyEvent.KEYCODE_DPAD_LEFT, 0, false, false));
// .. shifted:
assertKeysEquals("\033[1;2A", KeyHandler.getCode(KeyEvent.KEYCODE_DPAD_UP, KeyHandler.KEYMOD_SHIFT, false, false));
assertKeysEquals("\033[1;2B", KeyHandler.getCode(KeyEvent.KEYCODE_DPAD_DOWN, KeyHandler.KEYMOD_SHIFT, false, false));
assertKeysEquals("\033[1;2C", KeyHandler.getCode(KeyEvent.KEYCODE_DPAD_RIGHT, KeyHandler.KEYMOD_SHIFT, false, false));
assertKeysEquals("\033[1;2D", KeyHandler.getCode(KeyEvent.KEYCODE_DPAD_LEFT, KeyHandler.KEYMOD_SHIFT, false, false));
// .. ctrl:ed:
assertKeysEquals("\033[1;5A", KeyHandler.getCode(KeyEvent.KEYCODE_DPAD_UP, KeyHandler.KEYMOD_CTRL, false, false));
assertKeysEquals("\033[1;5B", KeyHandler.getCode(KeyEvent.KEYCODE_DPAD_DOWN, KeyHandler.KEYMOD_CTRL, false, false));
assertKeysEquals("\033[1;5C", KeyHandler.getCode(KeyEvent.KEYCODE_DPAD_RIGHT, KeyHandler.KEYMOD_CTRL, false, false));
assertKeysEquals("\033[1;5D", KeyHandler.getCode(KeyEvent.KEYCODE_DPAD_LEFT, KeyHandler.KEYMOD_CTRL, false, false));
// .. ctrl:ed and shifted:
int mod = KeyHandler.KEYMOD_CTRL | KeyHandler.KEYMOD_SHIFT;
assertKeysEquals("\033[1;6A", KeyHandler.getCode(KeyEvent.KEYCODE_DPAD_UP, mod, false, false));
assertKeysEquals("\033[1;6B", KeyHandler.getCode(KeyEvent.KEYCODE_DPAD_DOWN, mod, false, false));
assertKeysEquals("\033[1;6C", KeyHandler.getCode(KeyEvent.KEYCODE_DPAD_RIGHT, mod, false, false));
assertKeysEquals("\033[1;6D", KeyHandler.getCode(KeyEvent.KEYCODE_DPAD_LEFT, mod, false, false));
// Home/end keys:
assertKeysEquals("\033[H", KeyHandler.getCode(KeyEvent.KEYCODE_MOVE_HOME, 0, false, false));
assertKeysEquals("\033[F", KeyHandler.getCode(KeyEvent.KEYCODE_MOVE_END, 0, false, false));
// ... shifted:
assertKeysEquals("\033[1;2H", KeyHandler.getCode(KeyEvent.KEYCODE_MOVE_HOME, KeyHandler.KEYMOD_SHIFT, false, false));
assertKeysEquals("\033[1;2F", KeyHandler.getCode(KeyEvent.KEYCODE_MOVE_END, KeyHandler.KEYMOD_SHIFT, false, false));
// Function keys F1-F12:
assertKeysEquals("\033OP", KeyHandler.getCode(KeyEvent.KEYCODE_F1, 0, false, false));
assertKeysEquals("\033OQ", KeyHandler.getCode(KeyEvent.KEYCODE_F2, 0, false, false));
assertKeysEquals("\033OR", KeyHandler.getCode(KeyEvent.KEYCODE_F3, 0, false, false));
assertKeysEquals("\033OS", KeyHandler.getCode(KeyEvent.KEYCODE_F4, 0, false, false));
assertKeysEquals("\033[15~", KeyHandler.getCode(KeyEvent.KEYCODE_F5, 0, false, false));
assertKeysEquals("\033[17~", KeyHandler.getCode(KeyEvent.KEYCODE_F6, 0, false, false));
assertKeysEquals("\033[18~", KeyHandler.getCode(KeyEvent.KEYCODE_F7, 0, false, false));
assertKeysEquals("\033[19~", KeyHandler.getCode(KeyEvent.KEYCODE_F8, 0, false, false));
assertKeysEquals("\033[20~", KeyHandler.getCode(KeyEvent.KEYCODE_F9, 0, false, false));
assertKeysEquals("\033[21~", KeyHandler.getCode(KeyEvent.KEYCODE_F10, 0, false, false));
assertKeysEquals("\033[23~", KeyHandler.getCode(KeyEvent.KEYCODE_F11, 0, false, false));
assertKeysEquals("\033[24~", KeyHandler.getCode(KeyEvent.KEYCODE_F12, 0, false, false));
// Function keys F13-F24 (same as shifted F1-F12):
assertKeysEquals("\033[1;2P", KeyHandler.getCode(KeyEvent.KEYCODE_F1, KeyHandler.KEYMOD_SHIFT, false, false));
assertKeysEquals("\033[1;2Q", KeyHandler.getCode(KeyEvent.KEYCODE_F2, KeyHandler.KEYMOD_SHIFT, false, false));
assertKeysEquals("\033[1;2R", KeyHandler.getCode(KeyEvent.KEYCODE_F3, KeyHandler.KEYMOD_SHIFT, false, false));
assertKeysEquals("\033[1;2S", KeyHandler.getCode(KeyEvent.KEYCODE_F4, KeyHandler.KEYMOD_SHIFT, false, false));
assertKeysEquals("\033[15;2~", KeyHandler.getCode(KeyEvent.KEYCODE_F5, KeyHandler.KEYMOD_SHIFT, false, false));
assertKeysEquals("\033[17;2~", KeyHandler.getCode(KeyEvent.KEYCODE_F6, KeyHandler.KEYMOD_SHIFT, false, false));
assertKeysEquals("\033[18;2~", KeyHandler.getCode(KeyEvent.KEYCODE_F7, KeyHandler.KEYMOD_SHIFT, false, false));
assertKeysEquals("\033[19;2~", KeyHandler.getCode(KeyEvent.KEYCODE_F8, KeyHandler.KEYMOD_SHIFT, false, false));
assertKeysEquals("\033[20;2~", KeyHandler.getCode(KeyEvent.KEYCODE_F9, KeyHandler.KEYMOD_SHIFT, false, false));
assertKeysEquals("\033[21;2~", KeyHandler.getCode(KeyEvent.KEYCODE_F10, KeyHandler.KEYMOD_SHIFT, false, false));
assertKeysEquals("\033[23;2~", KeyHandler.getCode(KeyEvent.KEYCODE_F11, KeyHandler.KEYMOD_SHIFT, false, false));
assertKeysEquals("\033[24;2~", KeyHandler.getCode(KeyEvent.KEYCODE_F12, KeyHandler.KEYMOD_SHIFT, false, false));
assertKeysEquals("0", KeyHandler.getCode(KeyEvent.KEYCODE_NUMPAD_0, 0, false, false));
assertKeysEquals("1", KeyHandler.getCode(KeyEvent.KEYCODE_NUMPAD_1, 0, false, false));
assertKeysEquals("2", KeyHandler.getCode(KeyEvent.KEYCODE_NUMPAD_2, 0, false, false));
assertKeysEquals("3", KeyHandler.getCode(KeyEvent.KEYCODE_NUMPAD_3, 0, false, false));
assertKeysEquals("4", KeyHandler.getCode(KeyEvent.KEYCODE_NUMPAD_4, 0, false, false));
assertKeysEquals("5", KeyHandler.getCode(KeyEvent.KEYCODE_NUMPAD_5, 0, false, false));
assertKeysEquals("6", KeyHandler.getCode(KeyEvent.KEYCODE_NUMPAD_6, 0, false, false));
assertKeysEquals("7", KeyHandler.getCode(KeyEvent.KEYCODE_NUMPAD_7, 0, false, false));
assertKeysEquals("8", KeyHandler.getCode(KeyEvent.KEYCODE_NUMPAD_8, 0, false, false));
assertKeysEquals("9", KeyHandler.getCode(KeyEvent.KEYCODE_NUMPAD_9, 0, false, false));
assertKeysEquals(",", KeyHandler.getCode(KeyEvent.KEYCODE_NUMPAD_COMMA, 0, false, false));
assertKeysEquals(".", KeyHandler.getCode(KeyEvent.KEYCODE_NUMPAD_DOT, 0, false, false));
}
}

View File

@@ -1,196 +0,0 @@
package com.termux.terminal;
import android.util.Base64;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
/** "ESC ]" is the Operating System Command. */
public class OperatingSystemControlTest extends TerminalTestCase {
public void testSetTitle() throws Exception {
List<ChangedTitle> expectedTitleChanges = new ArrayList<>();
withTerminalSized(10, 10);
enterString("\033]0;Hello, world\007");
assertEquals("Hello, world", mTerminal.getTitle());
expectedTitleChanges.add(new ChangedTitle(null, "Hello, world"));
assertEquals(expectedTitleChanges, mOutput.titleChanges);
enterString("\033]0;Goodbye, world\007");
assertEquals("Goodbye, world", mTerminal.getTitle());
expectedTitleChanges.add(new ChangedTitle("Hello, world", "Goodbye, world"));
assertEquals(expectedTitleChanges, mOutput.titleChanges);
enterString("\033]0;Goodbye, \u00F1 world\007");
assertEquals("Goodbye, \uu00F1 world", mTerminal.getTitle());
expectedTitleChanges.add(new ChangedTitle("Goodbye, world", "Goodbye, \uu00F1 world"));
assertEquals(expectedTitleChanges, mOutput.titleChanges);
// 2 should work as well (0 sets both title and icon).
enterString("\033]2;Updated\007");
assertEquals("Updated", mTerminal.getTitle());
expectedTitleChanges.add(new ChangedTitle("Goodbye, \uu00F1 world", "Updated"));
assertEquals(expectedTitleChanges, mOutput.titleChanges);
enterString("\033[22;0t");
enterString("\033]0;FIRST\007");
expectedTitleChanges.add(new ChangedTitle("Updated", "FIRST"));
assertEquals("FIRST", mTerminal.getTitle());
assertEquals(expectedTitleChanges, mOutput.titleChanges);
enterString("\033[22;0t");
enterString("\033]0;SECOND\007");
assertEquals("SECOND", mTerminal.getTitle());
expectedTitleChanges.add(new ChangedTitle("FIRST", "SECOND"));
assertEquals(expectedTitleChanges, mOutput.titleChanges);
enterString("\033[23;0t");
assertEquals("FIRST", mTerminal.getTitle());
expectedTitleChanges.add(new ChangedTitle("SECOND", "FIRST"));
assertEquals(expectedTitleChanges, mOutput.titleChanges);
enterString("\033[23;0t");
expectedTitleChanges.add(new ChangedTitle("FIRST", "Updated"));
assertEquals(expectedTitleChanges, mOutput.titleChanges);
enterString("\033[22;0t");
enterString("\033[22;0t");
enterString("\033[22;0t");
// Popping to same title should not cause changes.
enterString("\033[23;0t");
enterString("\033[23;0t");
enterString("\033[23;0t");
assertEquals(expectedTitleChanges, mOutput.titleChanges);
}
public void testTitleStack() throws Exception {
// echo -ne '\e]0;BEFORE\007' # set title
// echo -ne '\e[22t' # push to stack
// echo -ne '\e]0;AFTER\007' # set new title
// echo -ne '\e[23t' # retrieve from stack
withTerminalSized(10, 10);
enterString("\033]0;InitialTitle\007");
assertEquals("InitialTitle", mTerminal.getTitle());
enterString("\033[22t");
assertEquals("InitialTitle", mTerminal.getTitle());
enterString("\033]0;UpdatedTitle\007");
assertEquals("UpdatedTitle", mTerminal.getTitle());
enterString("\033[23t");
assertEquals("InitialTitle", mTerminal.getTitle());
enterString("\033[23t\033[23t\033[23t");
assertEquals("InitialTitle", mTerminal.getTitle());
}
public void testSetColor() throws Exception {
// "OSC 4; $INDEX; $COLORSPEC BEL" => Change color $INDEX to the color specified by $COLORSPEC.
withTerminalSized(4, 4).enterString("\033]4;5;#00FF00\007");
assertEquals(Integer.toHexString(0xFF00FF00), Integer.toHexString(mTerminal.mColors.mCurrentColors[5]));
enterString("\033]4;5;#00FFAB\007");
assertEquals(mTerminal.mColors.mCurrentColors[5], 0xFF00FFAB);
enterString("\033]4;255;#ABFFAB\007");
assertEquals(mTerminal.mColors.mCurrentColors[255], 0xFFABFFAB);
// Two indexed colors at once:
enterString("\033]4;7;#00FF00;8;#0000FF\007");
assertEquals(mTerminal.mColors.mCurrentColors[7], 0xFF00FF00);
assertEquals(mTerminal.mColors.mCurrentColors[8], 0xFF0000FF);
}
void assertIndexColorsMatch(int[] expected) {
for (int i = 0; i < 255; i++)
assertEquals("index=" + i, expected[i], mTerminal.mColors.mCurrentColors[i]);
}
public void testResetColor() throws Exception {
withTerminalSized(4, 4);
int[] initialColors = new int[TextStyle.NUM_INDEXED_COLORS];
System.arraycopy(mTerminal.mColors.mCurrentColors, 0, initialColors, 0, initialColors.length);
int[] expectedColors = new int[initialColors.length];
System.arraycopy(mTerminal.mColors.mCurrentColors, 0, expectedColors, 0, expectedColors.length);
Random rand = new Random();
for (int endType = 0; endType < 3; endType++) {
// Both BEL (7) and ST (ESC \) can end an OSC sequence.
String ender = (endType == 0) ? "\007" : "\033\\";
for (int i = 0; i < 255; i++) {
expectedColors[i] = 0xFF000000 + (rand.nextInt() & 0xFFFFFF);
int r = (expectedColors[i] >> 16) & 0xFF;
int g = (expectedColors[i] >> 8) & 0xFF;
int b = expectedColors[i] & 0xFF;
String rgbHex = String.format("%02x", r) + String.format("%02x", g) + String.format("%02x", b);
enterString("\033]4;" + i + ";#" + rgbHex + ender);
assertEquals(expectedColors[i], mTerminal.mColors.mCurrentColors[i]);
}
}
enterString("\033]104;0\007");
expectedColors[0] = TerminalColors.COLOR_SCHEME.mDefaultColors[0];
assertIndexColorsMatch(expectedColors);
enterString("\033]104;1;2\007");
expectedColors[1] = TerminalColors.COLOR_SCHEME.mDefaultColors[1];
expectedColors[2] = TerminalColors.COLOR_SCHEME.mDefaultColors[2];
assertIndexColorsMatch(expectedColors);
enterString("\033]104\007"); // Reset all colors.
assertIndexColorsMatch(TerminalColors.COLOR_SCHEME.mDefaultColors);
}
public void disabledTestSetClipboard() {
// Cannot run this as a unit test since Base64 is a android.util class.
enterString("\033]52;c;" + Base64.encodeToString("Hello, world".getBytes(), 0) + "\007");
}
public void testResettingTerminalResetsColor() throws Exception {
// "OSC 4; $INDEX; $COLORSPEC BEL" => Change color $INDEX to the color specified by $COLORSPEC.
withTerminalSized(4, 4).enterString("\033]4;5;#00FF00\007");
enterString("\033]4;5;#00FFAB\007").assertColor(5, 0xFF00FFAB);
enterString("\033]4;255;#ABFFAB\007").assertColor(255, 0xFFABFFAB);
mTerminal.reset();
assertIndexColorsMatch(TerminalColors.COLOR_SCHEME.mDefaultColors);
}
public void testSettingDynamicColors() {
// "${OSC}${DYNAMIC};${COLORSPEC}${BEL_OR_STRINGTERMINATOR}" => Change ${DYNAMIC} color to the color specified by $COLORSPEC where:
// DYNAMIC=10: Text foreground color.
// DYNAMIC=11: Text background color.
// DYNAMIC=12: Text cursor color.
withTerminalSized(3, 3).enterString("\033]10;#ABCD00\007").assertColor(TextStyle.COLOR_INDEX_FOREGROUND, 0xFFABCD00);
enterString("\033]11;#0ABCD0\007").assertColor(TextStyle.COLOR_INDEX_BACKGROUND, 0xFF0ABCD0);
enterString("\033]12;#00ABCD\007").assertColor(TextStyle.COLOR_INDEX_CURSOR, 0xFF00ABCD);
// Two special colors at once
// ("Each successive parameter changes the next color in the list. The value of P s tells the starting point in the list"):
enterString("\033]10;#FF0000;#00FF00\007").assertColor(TextStyle.COLOR_INDEX_FOREGROUND, 0xFFFF0000);
assertColor(TextStyle.COLOR_INDEX_BACKGROUND, 0xFF00FF00);
// Three at once:
enterString("\033]10;#0000FF;#00FF00;#FF0000\007").assertColor(TextStyle.COLOR_INDEX_FOREGROUND, 0xFF0000FF);
assertColor(TextStyle.COLOR_INDEX_BACKGROUND, 0xFF00FF00).assertColor(TextStyle.COLOR_INDEX_CURSOR, 0xFFFF0000);
// Without ending semicolon:
enterString("\033]10;#FF0000\007").assertColor(TextStyle.COLOR_INDEX_FOREGROUND, 0xFFFF0000);
// For background and cursor:
enterString("\033]11;#FFFF00;\007").assertColor(TextStyle.COLOR_INDEX_BACKGROUND, 0xFFFFFF00);
enterString("\033]12;#00FFFF;\007").assertColor(TextStyle.COLOR_INDEX_CURSOR, 0xFF00FFFF);
// Using string terminator:
String stringTerminator = "\033\\";
enterString("\033]10;#FF0000" + stringTerminator).assertColor(TextStyle.COLOR_INDEX_FOREGROUND, 0xFFFF0000);
// For background and cursor:
enterString("\033]11;#FFFF00;" + stringTerminator).assertColor(TextStyle.COLOR_INDEX_BACKGROUND, 0xFFFFFF00);
enterString("\033]12;#00FFFF;" + stringTerminator).assertColor(TextStyle.COLOR_INDEX_CURSOR, 0xFF00FFFF);
}
public void testReportSpecialColors() {
// "${OSC}${DYNAMIC};?${BEL}" => Terminal responds with the control sequence which would set the current color.
// Both xterm and libvte (gnome-terminal and others) use the longest color representation, which means that
// the response is "${OSC}rgb:RRRR/GGGG/BBBB"
withTerminalSized(3, 3).enterString("\033]10;#ABCD00\007").assertColor(TextStyle.COLOR_INDEX_FOREGROUND, 0xFFABCD00);
assertEnteringStringGivesResponse("\033]10;?\007", "\033]10;rgb:abab/cdcd/0000\007");
// Same as above but with string terminator. xterm uses the same string terminator in the response, which
// e.g. script posted at http://superuser.com/questions/157563/programmatic-access-to-current-xterm-background-color
// relies on:
assertEnteringStringGivesResponse("\033]10;?\033\\", "\033]10;rgb:abab/cdcd/0000\033\\");
}
}

View File

@@ -1,117 +0,0 @@
package com.termux.terminal;
public class RectangularAreasTest extends TerminalTestCase {
/** http://www.vt100.net/docs/vt510-rm/DECFRA */
public void testFillRectangularArea() {
withTerminalSized(3, 3).enterString("\033[88$x").assertLinesAre("XXX", "XXX", "XXX");
withTerminalSized(3, 3).enterString("\033[88;1;1;2;10$x").assertLinesAre("XXX", "XXX", " ");
withTerminalSized(3, 3).enterString("\033[88;2;1;3;10$x").assertLinesAre(" ", "XXX", "XXX");
withTerminalSized(3, 3).enterString("\033[88;1;1;100;1$x").assertLinesAre("X ", "X ", "X ");
withTerminalSized(3, 3).enterString("\033[88;1;1;100;2$x").assertLinesAre("XX ", "XX ", "XX ");
withTerminalSized(3, 3).enterString("\033[88;100;1;100;2$x").assertLinesAre(" ", " ", " ");
}
/** http://www.vt100.net/docs/vt510-rm/DECERA */
public void testEraseRectangularArea() {
withTerminalSized(3, 3).enterString("ABCDEFGHI\033[$z").assertLinesAre(" ", " ", " ");
withTerminalSized(3, 3).enterString("ABCDEFGHI\033[1;1;2;10$z").assertLinesAre(" ", " ", "GHI");
withTerminalSized(3, 3).enterString("ABCDEFGHI\033[2;1;3;10$z").assertLinesAre("ABC", " ", " ");
withTerminalSized(3, 3).enterString("ABCDEFGHI\033[1;1;100;1$z").assertLinesAre(" BC", " EF", " HI");
withTerminalSized(3, 3).enterString("ABCDEFGHI\033[1;1;100;2$z").assertLinesAre(" C", " F", " I");
withTerminalSized(3, 3).enterString("ABCDEFGHI\033[100;1;100;2$z").assertLinesAre("ABC", "DEF", "GHI");
withTerminalSized(3, 3).enterString("A\033[$zBC").assertLinesAre(" BC", " ", " ");
}
/** http://www.vt100.net/docs/vt510-rm/DECSED */
public void testSelectiveEraseInDisplay() {
// ${CSI}1"q enables protection, ${CSI}0"q disables it.
// ${CSI}?${0,1,2}J" erases (0=cursor to end, 1=start to cursor, 2=complete display).
withTerminalSized(3, 3).enterString("ABCDEFGHI\033[?2J").assertLinesAre(" ", " ", " ");
withTerminalSized(3, 3).enterString("ABC\033[1\"qDE\033[0\"qFGHI\033[?2J").assertLinesAre(" ", "DE ", " ");
withTerminalSized(3, 3).enterString("\033[1\"qABCDE\033[0\"qFGHI\033[?2J").assertLinesAre("ABC", "DE ", " ");
}
/** http://vt100.net/docs/vt510-rm/DECSEL */
public void testSelectiveEraseInLine() {
// ${CSI}1"q enables protection, ${CSI}0"q disables it.
// ${CSI}?${0,1,2}K" erases (0=cursor to end, 1=start to cursor, 2=complete line).
withTerminalSized(3, 3).enterString("ABCDEFGHI\033[?2K").assertLinesAre("ABC", "DEF", " ");
withTerminalSized(3, 3).enterString("ABCDE\033[?0KFGHI").assertLinesAre("ABC", "DEF", "GHI");
withTerminalSized(3, 3).enterString("ABCDE\033[?1KFGHI").assertLinesAre("ABC", " F", "GHI");
withTerminalSized(3, 3).enterString("ABCDE\033[?2KFGHI").assertLinesAre("ABC", " F", "GHI");
withTerminalSized(3, 3).enterString("ABCDEFGHI\033[2;2H\033[?0K").assertLinesAre("ABC", "D ", "GHI");
withTerminalSized(3, 3).enterString("ABC\033[1\"qD\033[0\"qE\033[?2KFGHI").assertLinesAre("ABC", "D F", "GHI");
}
/** http://www.vt100.net/docs/vt510-rm/DECSERA */
public void testSelectiveEraseInRectangle() {
// ${CSI}1"q enables protection, ${CSI}0"q disables it.
// ${CSI}?${TOP};${LEFT};${BOTTOM};${RIGHT}${" erases.
withTerminalSized(3, 3).enterString("ABCDEFGHI\033[${").assertLinesAre(" ", " ", " ");
withTerminalSized(3, 3).enterString("ABCDEFGHI\033[1;1;2;10${").assertLinesAre(" ", " ", "GHI");
withTerminalSized(3, 3).enterString("ABCDEFGHI\033[2;1;3;10${").assertLinesAre("ABC", " ", " ");
withTerminalSized(3, 3).enterString("ABCDEFGHI\033[1;1;100;1${").assertLinesAre(" BC", " EF", " HI");
withTerminalSized(3, 3).enterString("ABCDEFGHI\033[1;1;100;2${").assertLinesAre(" C", " F", " I");
withTerminalSized(3, 3).enterString("ABCDEFGHI\033[100;1;100;2${").assertLinesAre("ABC", "DEF", "GHI");
withTerminalSized(3, 3).enterString("ABCD\033[1\"qE\033[0\"qFGHI\033[${").assertLinesAre(" ", " E ", " ");
withTerminalSized(3, 3).enterString("ABCD\033[1\"qE\033[0\"qFGHI\033[1;1;2;10${").assertLinesAre(" ", " E ", "GHI");
}
/** http://vt100.net/docs/vt510-rm/DECCRA */
public void testRectangularCopy() {
// "${CSI}${SRC_TOP};${SRC_LEFT};${SRC_BOTTOM};${SRC_RIGHT};${SRC_PAGE};${DST_TOP};${DST_LEFT};${DST_PAGE}\$v"
withTerminalSized(7, 3).enterString("ABC\r\nDEF\r\nGHI\033[1;1;2;2;1;2;5;1$v").assertLinesAre("ABC ", "DEF AB ", "GHI DE ");
withTerminalSized(7, 3).enterString("ABC\r\nDEF\r\nGHI\033[1;1;3;3;1;1;4;1$v").assertLinesAre("ABCABC ", "DEFDEF ", "GHIGHI ");
withTerminalSized(7, 3).enterString("ABC\r\nDEF\r\nGHI\033[1;1;3;3;1;1;3;1$v").assertLinesAre("ABABC ", "DEDEF ", "GHGHI ");
withTerminalSized(7, 3).enterString(" ABC\r\n DEF\r\n GHI\033[1;4;3;6;1;1;1;1$v").assertLinesAre("ABCABC ", "DEFDEF ",
"GHIGHI ");
withTerminalSized(7, 3).enterString(" ABC\r\n DEF\r\n GHI\033[1;4;3;6;1;1;2;1$v").assertLinesAre(" ABCBC ", " DEFEF ",
" GHIHI ");
withTerminalSized(3, 3).enterString("ABC\r\nDEF\r\nGHI\033[1;1;2;2;1;2;2;1$v").assertLinesAre("ABC", "DAB", "GDE");
// Enable ${CSI}?6h origin mode (DECOM) and ${CSI}?69h for left/right margin (DECLRMM) enabling, ${CSI}${LEFTMARGIN};${RIGHTMARGIN}s
// for DECSLRM margin setting.
withTerminalSized(5, 5).enterString("\033[?6h\033[?69h\033[2;4s");
enterString("ABCDEFGHIJK").assertLinesAre(" ABC ", " DEF ", " GHI ", " JK ", " ");
enterString("\033[1;1;2;2;1;2;2;1$v").assertLinesAre(" ABC ", " DAB ", " GDE ", " JK ", " ");
}
/** http://vt100.net/docs/vt510-rm/DECCARA */
public void testChangeAttributesInRectangularArea() {
final int b = TextStyle.CHARACTER_ATTRIBUTE_BOLD;
// "${CSI}${TOP};${LEFT};${BOTTOM};${RIGHT};${ATTRIBUTES}\$r"
withTerminalSized(3, 3).enterString("ABCDEFGHI\033[1;1;2;2;1$r").assertLinesAre("ABC", "DEF", "GHI");
assertEffectAttributesSet(effectLine(b, b, b), effectLine(b, b, 0), effectLine(0, 0, 0));
// Now with http://www.vt100.net/docs/vt510-rm/DECSACE ("${CSI}2*x") specifying rectangle:
withTerminalSized(3, 3).enterString("\033[2*xABCDEFGHI\033[1;1;2;2;1$r").assertLinesAre("ABC", "DEF", "GHI");
assertEffectAttributesSet(effectLine(b, b, 0), effectLine(b, b, 0), effectLine(0, 0, 0));
}
/** http://vt100.net/docs/vt510-rm/DECCARA */
public void testReverseAttributesInRectangularArea() {
final int b = TextStyle.CHARACTER_ATTRIBUTE_BOLD;
final int u = TextStyle.CHARACTER_ATTRIBUTE_UNDERLINE;
final int bu = TextStyle.CHARACTER_ATTRIBUTE_BOLD | TextStyle.CHARACTER_ATTRIBUTE_UNDERLINE;
// "${CSI}${TOP};${LEFT};${BOTTOM};${RIGHT};${ATTRIBUTES}\$t"
withTerminalSized(3, 3).enterString("ABCDEFGHI\033[1;1;2;2;1$t").assertLinesAre("ABC", "DEF", "GHI");
assertEffectAttributesSet(effectLine(b, b, b), effectLine(b, b, 0), effectLine(0, 0, 0));
// Now with http://www.vt100.net/docs/vt510-rm/DECSACE ("${CSI}2*x") specifying rectangle:
withTerminalSized(3, 3).enterString("\033[2*xABCDEFGHI\033[1;1;2;2;1$t").assertLinesAre("ABC", "DEF", "GHI");
assertEffectAttributesSet(effectLine(b, b, 0), effectLine(b, b, 0), effectLine(0, 0, 0));
// Check reversal by initially bolding the B:
withTerminalSized(3, 3).enterString("\033[2*xA\033[1mB\033[0mCDEFGHI\033[1;1;2;2;1$t").assertLinesAre("ABC", "DEF", "GHI");
assertEffectAttributesSet(effectLine(b, 0, 0), effectLine(b, b, 0), effectLine(0, 0, 0));
// Check reversal by initially underlining A, bolding B, then reversing both bold and underline:
withTerminalSized(3, 3).enterString("\033[2*x\033[4mA\033[0m\033[1mB\033[0mCDEFGHI\033[1;1;2;2;1;4$t").assertLinesAre("ABC", "DEF",
"GHI");
assertEffectAttributesSet(effectLine(b, u, 0), effectLine(bu, bu, 0), effectLine(0, 0, 0));
}
}

View File

@@ -1,212 +0,0 @@
package com.termux.terminal;
public class ResizeTest extends TerminalTestCase {
public void testResizeWhenHasHistory() {
final int cols = 3;
withTerminalSized(cols, 3).enterString("111222333444555666777888999").assertCursorAt(2, 2).assertLinesAre("777", "888", "999");
resize(cols, 5).assertCursorAt(4, 2).assertLinesAre("555", "666", "777", "888", "999");
resize(cols, 3).assertCursorAt(2, 2).assertLinesAre("777", "888", "999");
}
public void testResizeWhenInAltBuffer() {
final int rows = 3, cols = 3;
withTerminalSized(cols, rows).enterString("a\r\ndef$").assertLinesAre("a ", "def", "$ ").assertCursorAt(2, 1);
// Resize and back again while in main buffer:
resize(cols, 5).assertLinesAre("a ", "def", "$ ", " ", " ").assertCursorAt(2, 1);
resize(cols, rows).assertLinesAre("a ", "def", "$ ").assertCursorAt(2, 1);
// Switch to alt buffer:
enterString("\033[?1049h").assertLinesAre(" ", " ", " ").assertCursorAt(2, 1);
enterString("h").assertLinesAre(" ", " ", " h ").assertCursorAt(2, 2);
resize(cols, 5).resize(cols, rows);
// Switch from alt buffer:
enterString("\033[?1049l").assertLinesAre("a ", "def", "$ ").assertCursorAt(2, 1);
}
public void testShrinkingInAltBuffer() {
final int rows = 5;
final int cols = 3;
withTerminalSized(cols, rows).enterString("A\r\nB\r\nC\r\nD\r\nE").assertLinesAre("A ", "B ", "C ", "D ", "E ");
enterString("\033[?1049h").assertLinesAre(" ", " ", " ", " ", " ");
resize(3, 3).enterString("\033[?1049lF").assertLinesAre("C ", "D ", "EF ");
}
public void testResizeAfterNewlineWhenInAltBuffer() {
final int rows = 3;
final int cols = 3;
withTerminalSized(cols, rows);
enterString("a\r\nb\r\nc\r\nd\r\ne\r\nf\r\n").assertLinesAre("e ", "f ", " ").assertCursorAt(2, 0);
assertLineWraps(false, false, false);
// Switch to alt buffer:
enterString("\033[?1049h").assertLinesAre(" ", " ", " ").assertCursorAt(2, 0);
enterString("h").assertLinesAre(" ", " ", "h ").assertCursorAt(2, 1);
// Grow by two rows:
resize(cols, 5).assertLinesAre(" ", " ", "h ", " ", " ").assertCursorAt(2, 1);
resize(cols, rows).assertLinesAre(" ", " ", "h ").assertCursorAt(2, 1);
// Switch from alt buffer:
enterString("\033[?1049l").assertLinesAre("e ", "f ", " ").assertCursorAt(2, 0);
}
public void testResizeAfterHistoryWraparound() {
final int rows = 3;
final int cols = 10;
withTerminalSized(cols, rows);
StringBuilder buffer = new StringBuilder();
for (int i = 0; i < 1000; i++) {
String s = Integer.toString(i);
enterString(s);
buffer.setLength(0);
buffer.append(s);
while (buffer.length() < cols)
buffer.append(' ');
if (i > rows) {
assertLineIs(rows - 1, buffer.toString());
}
enterString("\r\n");
}
assertLinesAre("998 ", "999 ", " ");
mTerminal.resize(cols, 2);
assertLinesAre("999 ", " ");
mTerminal.resize(cols, 5);
assertLinesAre("996 ", "997 ", "998 ", "999 ", " ");
mTerminal.resize(cols, rows);
assertLinesAre("998 ", "999 ", " ");
}
public void testVerticalResize() {
final int rows = 5;
final int cols = 3;
withTerminalSized(cols, rows);
// Foreground color to 119:
enterString("\033[38;5;119m");
// Background color to 129:
enterString("\033[48;5;129m");
// Clear with ED, Erase in Display:
enterString("\033[2J");
for (int r = 0; r < rows; r++) {
for (int c = 0; c < cols; c++) {
long style = getStyleAt(r, c);
assertEquals(119, TextStyle.decodeForeColor(style));
assertEquals(129, TextStyle.decodeBackColor(style));
}
}
enterString("11\r\n22");
assertLinesAre("11 ", "22 ", " ", " ", " ").assertLineWraps(false, false, false, false, false);
resize(cols, rows - 2).assertLinesAre("11 ", "22 ", " ");
// After resize, screen should still be same color:
for (int r = 0; r < rows - 2; r++) {
for (int c = 0; c < cols; c++) {
long style = getStyleAt(r, c);
assertEquals(119, TextStyle.decodeForeColor(style));
assertEquals(129, TextStyle.decodeBackColor(style));
}
}
// Background color to 200 and grow back size (which should be cleared to the new background color):
enterString("\033[48;5;200m");
resize(cols, rows);
for (int r = 0; r < rows; r++) {
for (int c = 0; c < cols; c++) {
long style = getStyleAt(r, c);
assertEquals(119, TextStyle.decodeForeColor(style));
assertEquals("wrong at row=" + r, r >= 3 ? 200 : 129, TextStyle.decodeBackColor(style));
}
}
}
public void testHorizontalResize() {
final int rows = 5;
final int cols = 5;
withTerminalSized(cols, rows);
// Background color to 129:
// enterString("\033[48;5;129m").assertLinesAre(" ", " ", " ", " ", " ");
enterString("1111\r\n2222\r\n3333\r\n4444\r\n5555").assertCursorAt(4, 4);
// assertEquals(129, TextStyle.decodeBackColor(getStyleAt(2, 2)));
assertLinesAre("1111 ", "2222 ", "3333 ", "4444 ", "5555 ").assertLineWraps(false, false, false, false, false);
resize(cols + 2, rows).assertLinesAre("1111 ", "2222 ", "3333 ", "4444 ", "5555 ").assertCursorAt(4, 4);
assertLineWraps(false, false, false, false, false);
resize(cols, rows).assertLinesAre("1111 ", "2222 ", "3333 ", "4444 ", "5555 ").assertCursorAt(4, 4);
assertLineWraps(false, false, false, false, false);
resize(cols - 1, rows).assertLinesAre("2222", "3333", "4444", "5555", " ").assertCursorAt(4, 0);
assertLineWraps(false, false, false, true, false);
resize(cols - 2, rows).assertLinesAre("3 ", "444", "4 ", "555", "5 ").assertCursorAt(4, 1);
assertLineWraps(false, true, false, true, false);
// Back to original size:
resize(cols, rows).assertLinesAre("1111 ", "2222 ", "3333 ", "4444 ", "5555 ").assertCursorAt(4, 4);
assertLineWraps(false, false, false, false, false);
}
public void testLineWrap() {
final int rows = 3, cols = 5;
withTerminalSized(cols, rows).enterString("111111").assertLinesAre("11111", "1 ", " ");
assertCursorAt(1, 1).assertLineWraps(true, false, false);
resize(7, rows).assertCursorAt(0, 6).assertLinesAre("111111 ", " ", " ").assertLineWraps(false, false, false);
resize(cols, rows).assertCursorAt(1, 1).assertLinesAre("11111", "1 ", " ").assertLineWraps(true, false, false);
enterString("2").assertLinesAre("11111", "12 ", " ").assertLineWraps(true, false, false);
enterString("123").assertLinesAre("11111", "12123", " ").assertLineWraps(true, false, false);
enterString("W").assertLinesAre("11111", "12123", "W ").assertLineWraps(true, true, false);
withTerminalSized(cols, rows).enterString("1234512345");
assertLinesAre("12345", "12345", " ").assertLineWraps(true, false, false);
enterString("W").assertLinesAre("12345", "12345", "W ").assertLineWraps(true, true, false);
}
public void testCursorPositionWhenShrinking() {
final int rows = 5, cols = 3;
withTerminalSized(cols, rows).enterString("$ ").assertLinesAre("$ ", " ", " ", " ", " ").assertCursorAt(0, 2);
resize(3, 3).assertLinesAre("$ ", " ", " ").assertCursorAt(0, 2);
resize(cols, rows).assertLinesAre("$ ", " ", " ", " ", " ").assertCursorAt(0, 2);
}
public void testResizeWithCombiningCharInLastColumn() {
withTerminalSized(3, 3).enterString("ABC\u0302DEF").assertLinesAre("ABC\u0302", "DEF", " ");
resize(4, 3).assertLinesAre("ABC\u0302D", "EF ", " ");
// Same as above but with colors:
withTerminalSized(3, 3).enterString("\033[37mA\033[35mB\033[33mC\u0302\033[32mD\033[31mE\033[34mF").assertLinesAre("ABC\u0302",
"DEF", " ");
resize(4, 3).assertLinesAre("ABC\u0302D", "EF ", " ");
assertForegroundIndices(effectLine(7, 5, 3, 2), effectLine(1, 4, 4, 4), effectLine(4, 4, 4, 4));
}
public void testResizeWithLineWrappingContinuing() {
withTerminalSized(5, 3).enterString("\r\nAB DE").assertLinesAre(" ", "AB DE", " ");
resize(4, 3).assertLinesAre("AB D", "E ", " ");
resize(3, 3).assertLinesAre("AB ", "DE ", " ");
resize(5, 3).assertLinesAre(" ", "AB DE", " ");
}
public void testResizeWithWideChars() {
final int rows = 3, cols = 4;
String twoCharsWidthOne = new String(Character.toChars(TerminalRowTest.TWO_JAVA_CHARS_DISPLAY_WIDTH_ONE_1));
withTerminalSized(cols, rows).enterString(twoCharsWidthOne).enterString("\r\n");
enterString(twoCharsWidthOne).assertLinesAre(twoCharsWidthOne + " ", twoCharsWidthOne + " ", " ");
resize(3, 3).assertLinesAre(twoCharsWidthOne + " ", twoCharsWidthOne + " ", " ");
enterString(twoCharsWidthOne).assertLinesAre(twoCharsWidthOne + " ", twoCharsWidthOne + twoCharsWidthOne + " ", " ");
}
public void testResizeWithMoreWideChars() {
final int rows = 4, cols = 5;
withTerminalSized(cols, rows).enterString("qqrr").assertLinesAre("qqrr ", " ", " ", " ");
resize(2, rows).assertLinesAre("qq", "rr", " ", " ");
resize(5, rows).assertLinesAre("qqrr ", " ", " ", " ");
withTerminalSized(cols, rows).enterString("").assertLinesAre(" ", " ", " ", " ");
resize(2, rows).assertLinesAre("", "", " ", " ");
resize(5, rows).assertLinesAre(" ", " ", " ", " ");
}
}

View File

@@ -1,40 +0,0 @@
package com.termux.terminal;
public class ScreenBufferTest extends TerminalTestCase {
public void testBasics() {
TerminalBuffer screen = new TerminalBuffer(5, 3, 3);
assertEquals("", screen.getTranscriptText());
screen.setChar(0, 0, 'a', 0);
assertEquals("a", screen.getTranscriptText());
screen.setChar(0, 0, 'b', 0);
assertEquals("b", screen.getTranscriptText());
screen.setChar(2, 0, 'c', 0);
assertEquals("b c", screen.getTranscriptText());
screen.setChar(2, 2, 'f', 0);
assertEquals("b c\n\n f", screen.getTranscriptText());
screen.blockSet(0, 0, 2, 2, 'X', 0);
}
public void testBlockSet() {
TerminalBuffer screen = new TerminalBuffer(5, 3, 3);
screen.blockSet(0, 0, 2, 2, 'X', 0);
assertEquals("XX\nXX", screen.getTranscriptText());
screen.blockSet(1, 1, 2, 2, 'Y', 0);
assertEquals("XX\nXYY\n YY", screen.getTranscriptText());
}
public void testGetSelectedText() {
withTerminalSized(5, 3).enterString("ABCDEFGHIJ").assertLinesAre("ABCDE", "FGHIJ", " ");
assertEquals("AB", mTerminal.getSelectedText(0, 0, 1, 0));
assertEquals("BC", mTerminal.getSelectedText(1, 0, 2, 0));
assertEquals("CDE", mTerminal.getSelectedText(2, 0, 4, 0));
assertEquals("FG", mTerminal.getSelectedText(0, 1, 1, 1));
assertEquals("GH", mTerminal.getSelectedText(1, 1, 2, 1));
assertEquals("HIJ", mTerminal.getSelectedText(2, 1, 4, 1));
assertEquals("ABCDEFG", mTerminal.getSelectedText(0, 0, 1, 1));
withTerminalSized(5, 3).enterString("ABCDE\r\nFGHIJ").assertLinesAre("ABCDE", "FGHIJ", " ");
assertEquals("ABCDE\nFG", mTerminal.getSelectedText(0, 0, 1, 1));
}
}

View File

@@ -1,101 +0,0 @@
package com.termux.terminal;
/**
* ${CSI}${top};${bottom}r" - set Scrolling Region [top;bottom] (default = full size of window) (DECSTBM).
* <p/>
* "DECSTBM moves the cursor to column 1, line 1 of the page" (http://www.vt100.net/docs/vt510-rm/DECSTBM).
*/
public class ScrollRegionTest extends TerminalTestCase {
public void testScrollRegionTop() {
withTerminalSized(3, 4).enterString("111222333444").assertLinesAre("111", "222", "333", "444");
enterString("\033[2r").assertCursorAt(0, 0);
enterString("\r\n\r\n\r\n\r\nCDEFGH").assertLinesAre("111", "444", "CDE", "FGH").assertHistoryStartsWith("333");
enterString("IJK").assertLinesAre("111", "CDE", "FGH", "IJK").assertHistoryStartsWith("444");
// Reset scroll region and enter line:
enterString("\033[r").enterString("\r\n\r\n\r\n").enterString("LMNOPQ").assertLinesAre("CDE", "FGH", "LMN", "OPQ");
}
public void testScrollRegionBottom() {
withTerminalSized(3, 4).enterString("111222333444");
assertLinesAre("111", "222", "333", "444");
enterString("\033[1;3r").assertCursorAt(0, 0);
enterString("\r\n\r\nCDEFGH").assertLinesAre("222", "CDE", "FGH", "444").assertHistoryStartsWith("111");
// Reset scroll region and enter line:
enterString("\033[r").enterString("\r\n\r\n\r\n").enterString("IJKLMN").assertLinesAre("CDE", "FGH", "IJK", "LMN");
}
public void testScrollRegionResetWithOriginMode() {
withTerminalSized(3, 4).enterString("111222333444");
assertLinesAre("111", "222", "333", "444");
// "\033[?6h" sets origin mode, so that the later DECSTBM resets cursor to below margin:
enterString("\033[?6h\033[2r").assertCursorAt(1, 0);
}
public void testScrollRegionLeft() {
// ${CSI}?69h for DECLRMM enabling, ${CSI}${LEFTMARGIN};${RIGHTMARGIN}s for DECSLRM margin setting.
withTerminalSized(3, 3).enterString("\033[?69h\033[2sABCDEFG").assertLinesAre("ABC", " DE", " FG");
enterString("HI").assertLinesAre("ADE", " FG", " HI").enterString("JK").assertLinesAre("AFG", " HI", " JK");
enterString("\n").assertLinesAre("AHI", " JK", " ");
}
public void testScrollRegionRight() {
// ${CSI}?69h for DECLRMM enabling, ${CSI}${LEFTMARGIN};${RIGHTMARGIN}s for DECSLRM margin setting.
withTerminalSized(3, 3).enterString("YYY\033[?69h\033[1;2sABCDEF").assertLinesAre("ABY", "CD ", "EF ");
enterString("GH").assertLinesAre("CDY", "EF ", "GH ").enterString("IJ").assertLinesAre("EFY", "GH ", "IJ ");
enterString("\n").assertLinesAre("GHY", "IJ ", " ");
}
public void testScrollRegionOnAllSides() {
// ${CSI}?69h for DECLRMM enabling, ${CSI}${LEFTMARGIN};${RIGHTMARGIN}s for DECSLRM margin setting.
withTerminalSized(4, 4).enterString("ABCDEFGHIJKLMNOP").assertLinesAre("ABCD", "EFGH", "IJKL", "MNOP");
// http://www.vt100.net/docs/vt510-rm/DECOM
enterString("\033[?6h\033[2;3r").assertCursorAt(1, 0);
enterString("\033[?69h\033[2;3s").assertCursorAt(1, 1);
enterString("QRST").assertLinesAre("ABCD", "EQRH", "ISTL", "MNOP");
enterString("UV").assertLinesAre("ABCD", "ESTH", "IUVL", "MNOP");
}
public void testDECCOLMResetsScrollMargin() {
// DECCOLM — Select 80 or 132 Columns per Page (http://www.vt100.net/docs/vt510-rm/DECCOLM) has the important
// side effect to clear scroll margins, which is useful for e.g. the "reset" utility to clear scroll margins.
withTerminalSized(3, 4).enterString("111222333444").assertLinesAre("111", "222", "333", "444");
enterString("\033[2r\033[?3h\r\nABCDEFGHIJKL").assertLinesAre("ABC", "DEF", "GHI", "JKL");
}
public void testScrollOutsideVerticalRegion() {
withTerminalSized(3, 4).enterString("\033[0;2rhi\033[4;0Hyou").assertLinesAre("hi ", " ", " ", "you");
//enterString("see").assertLinesAre("hi ", " ", " ", "see");
}
public void testNELRespectsLeftMargin() {
// vttest "Menu 11.3.2: VT420 Cursor-Movement Test", select "10. Test other movement (CR/HT/LF/FF) within margins".
// The NEL (ESC E) sequence moves cursor to first position on next line, where first position depends on origin mode and margin.
withTerminalSized(3, 3).enterString("\033[?69h\033[2sABC\033ED").assertLinesAre("ABC", "D ", " ");
withTerminalSized(3, 3).enterString("\033[?69h\033[2sABC\033[?6h\033ED").assertLinesAre("ABC", " D ", " ");
}
public void testBackwardIndex() {
// vttest "Menu 11.3.2: VT420 Cursor-Movement Test", test 7.
// Without margins:
withTerminalSized(3, 3).enterString("ABCDEF\0336H").assertLinesAre("ABC", "DHF", " ");
enterString("\0336\0336I").assertLinesAre("ABC", "IHF", " ");
enterString("\0336\0336").assertLinesAre(" AB", " IH", " ");
// With left margin:
withTerminalSized(3, 3).enterString("\033[?69h\033[2sABCDEF\0336\0336").assertLinesAre("A B", " D", " F");
}
public void testForwardIndex() {
// vttest "Menu 11.3.2: VT420 Cursor-Movement Test", test 8.
// Without margins:
withTerminalSized(3, 3).enterString("ABCD\0339E").assertLinesAre("ABC", "D E", " ");
enterString("\0339").assertLinesAre("BC ", " E ", " ");
// With right margin:
withTerminalSized(3, 3).enterString("\033[?69h\033[0;2sABCD\0339").assertLinesAre("B ", "D ", " ");
}
public void testScrollDownWithScrollRegion() {
withTerminalSized(2, 5).enterString("1\r\n2\r\n3\r\n4\r\n5").assertLinesAre("1 ", "2 ", "3 ", "4 ", "5 ");
enterString("\033[3r").enterString("\033[2T").assertLinesAre("1 ", "2 ", " ", " ", "3 ");
}
}

View File

@@ -1,431 +0,0 @@
package com.termux.terminal;
import junit.framework.TestCase;
import java.util.Arrays;
import java.util.Random;
public class TerminalRowTest extends TestCase {
/** The properties of these code points are validated in {@link #testStaticConstants()}. */
private static final int ONE_JAVA_CHAR_DISPLAY_WIDTH_TWO_1 = 0x679C;
private static final int ONE_JAVA_CHAR_DISPLAY_WIDTH_TWO_2 = 0x679D;
private static final int TWO_JAVA_CHARS_DISPLAY_WIDTH_TWO_1 = 0x2070E;
private static final int TWO_JAVA_CHARS_DISPLAY_WIDTH_TWO_2 = 0x20731;
/** Unicode Character 'MUSICAL SYMBOL G CLEF' (U+1D11E). Two java chars required for this. */
static final int TWO_JAVA_CHARS_DISPLAY_WIDTH_ONE_1 = 0x1D11E;
/** Unicode Character 'MUSICAL SYMBOL G CLEF OTTAVA ALTA' (U+1D11F). Two java chars required for this. */
private static final int TWO_JAVA_CHARS_DISPLAY_WIDTH_ONE_2 = 0x1D11F;
private final int COLUMNS = 80;
/** A combining character. */
private static final int DIARESIS_CODEPOINT = 0x0308;
private TerminalRow row;
@Override
protected void setUp() throws Exception {
row = new TerminalRow(COLUMNS, TextStyle.NORMAL);
}
private void assertLineStartsWith(int... codePoints) {
char[] chars = row.mText;
int charIndex = 0;
for (int i = 0; i < codePoints.length; i++) {
int lineCodePoint = chars[charIndex++];
if (Character.isHighSurrogate((char) lineCodePoint)) {
lineCodePoint = Character.toCodePoint((char) lineCodePoint, chars[charIndex++]);
}
assertEquals("Differing a code point index=" + i, codePoints[i], lineCodePoint);
}
}
private void assertColumnCharIndicesStartsWith(int... indices) {
for (int i = 0; i < indices.length; i++) {
int expected = indices[i];
int actual = row.findStartOfColumn(i);
assertEquals("At index=" + i, expected, actual);
}
}
public void testSimpleDiaresis() {
row.setChar(0, DIARESIS_CODEPOINT, 0);
assertEquals(81, row.getSpaceUsed());
row.setChar(0, DIARESIS_CODEPOINT, 0);
assertEquals(82, row.getSpaceUsed());
assertLineStartsWith(' ', DIARESIS_CODEPOINT, DIARESIS_CODEPOINT, ' ');
}
public void testStaticConstants() {
assertEquals(1, Character.charCount(ONE_JAVA_CHAR_DISPLAY_WIDTH_TWO_1));
assertEquals(1, Character.charCount(ONE_JAVA_CHAR_DISPLAY_WIDTH_TWO_2));
assertEquals(2, WcWidth.width(ONE_JAVA_CHAR_DISPLAY_WIDTH_TWO_1));
assertEquals(2, WcWidth.width(ONE_JAVA_CHAR_DISPLAY_WIDTH_TWO_2));
assertEquals(2, Character.charCount(TWO_JAVA_CHARS_DISPLAY_WIDTH_ONE_1));
assertEquals(2, Character.charCount(TWO_JAVA_CHARS_DISPLAY_WIDTH_ONE_2));
assertEquals(1, WcWidth.width(TWO_JAVA_CHARS_DISPLAY_WIDTH_ONE_1));
assertEquals(1, WcWidth.width(TWO_JAVA_CHARS_DISPLAY_WIDTH_ONE_2));
assertEquals(2, Character.charCount(TWO_JAVA_CHARS_DISPLAY_WIDTH_TWO_1));
assertEquals(2, Character.charCount(TWO_JAVA_CHARS_DISPLAY_WIDTH_TWO_2));
assertEquals(2, WcWidth.width(TWO_JAVA_CHARS_DISPLAY_WIDTH_TWO_1));
assertEquals(2, WcWidth.width(TWO_JAVA_CHARS_DISPLAY_WIDTH_TWO_2));
assertEquals(1, Character.charCount(DIARESIS_CODEPOINT));
assertEquals(0, WcWidth.width(DIARESIS_CODEPOINT));
}
public void testOneColumn() {
assertEquals(0, row.findStartOfColumn(0));
row.setChar(0, 'a', 0);
assertEquals(0, row.findStartOfColumn(0));
}
public void testAscii() {
assertEquals(0, row.findStartOfColumn(0));
row.setChar(0, 'a', 0);
assertLineStartsWith('a', ' ', ' ');
assertEquals(1, row.findStartOfColumn(1));
assertEquals(80, row.getSpaceUsed());
row.setChar(0, 'b', 0);
assertEquals(1, row.findStartOfColumn(1));
assertEquals(2, row.findStartOfColumn(2));
assertEquals(80, row.getSpaceUsed());
assertColumnCharIndicesStartsWith(0, 1, 2, 3);
char[] someChars = new char[]{'a', 'c', 'e', '4', '5', '6', '7', '8'};
char[] rawLine = new char[80];
Arrays.fill(rawLine, ' ');
Random random = new Random();
for (int i = 0; i < 1000; i++) {
int lineIndex = random.nextInt(rawLine.length);
int charIndex = random.nextInt(someChars.length);
rawLine[lineIndex] = someChars[charIndex];
row.setChar(lineIndex, someChars[charIndex], 0);
}
char[] lineChars = row.mText;
for (int i = 0; i < rawLine.length; i++) {
assertEquals(rawLine[i], lineChars[i]);
}
}
public void testUnicode() {
assertEquals(0, row.findStartOfColumn(0));
assertEquals(80, row.getSpaceUsed());
row.setChar(0, TWO_JAVA_CHARS_DISPLAY_WIDTH_ONE_1, 0);
assertEquals(81, row.getSpaceUsed());
assertEquals(0, row.findStartOfColumn(0));
assertEquals(2, row.findStartOfColumn(1));
assertLineStartsWith(TWO_JAVA_CHARS_DISPLAY_WIDTH_ONE_1, ' ', ' ');
assertColumnCharIndicesStartsWith(0, 2, 3, 4);
row.setChar(0, 'a', 0);
assertEquals(80, row.getSpaceUsed());
assertEquals(0, row.findStartOfColumn(0));
assertEquals(1, row.findStartOfColumn(1));
assertLineStartsWith('a', ' ', ' ');
assertColumnCharIndicesStartsWith(0, 1, 2, 3);
row.setChar(0, TWO_JAVA_CHARS_DISPLAY_WIDTH_ONE_1, 0);
row.setChar(1, 'a', 0);
assertLineStartsWith(TWO_JAVA_CHARS_DISPLAY_WIDTH_ONE_1, 'a', ' ');
row.setChar(0, TWO_JAVA_CHARS_DISPLAY_WIDTH_ONE_1, 0);
row.setChar(1, TWO_JAVA_CHARS_DISPLAY_WIDTH_ONE_2, 0);
assertLineStartsWith(TWO_JAVA_CHARS_DISPLAY_WIDTH_ONE_1, TWO_JAVA_CHARS_DISPLAY_WIDTH_ONE_2, ' ');
assertColumnCharIndicesStartsWith(0, 2, 4, 5);
assertEquals(82, row.getSpaceUsed());
}
public void testDoubleWidth() {
row.setChar(0, 'a', 0);
row.setChar(1, ONE_JAVA_CHAR_DISPLAY_WIDTH_TWO_2, 0);
assertLineStartsWith('a', ONE_JAVA_CHAR_DISPLAY_WIDTH_TWO_2, ' ');
assertColumnCharIndicesStartsWith(0, 1, 1, 2);
row.setChar(0, ONE_JAVA_CHAR_DISPLAY_WIDTH_TWO_1, 0);
assertLineStartsWith(ONE_JAVA_CHAR_DISPLAY_WIDTH_TWO_1, ' ', ' ');
assertColumnCharIndicesStartsWith(0, 0, 1, 2);
row.setChar(0, ' ', 0);
assertLineStartsWith(' ', ' ', ' ', ' ');
assertColumnCharIndicesStartsWith(0, 1, 2, 3, 4);
row.setChar(0, ONE_JAVA_CHAR_DISPLAY_WIDTH_TWO_1, 0);
row.setChar(2, ONE_JAVA_CHAR_DISPLAY_WIDTH_TWO_2, 0);
assertLineStartsWith(ONE_JAVA_CHAR_DISPLAY_WIDTH_TWO_1, ONE_JAVA_CHAR_DISPLAY_WIDTH_TWO_2);
assertColumnCharIndicesStartsWith(0, 0, 1, 1, 2);
row.setChar(0, 'a', 0);
assertLineStartsWith('a', ' ', ONE_JAVA_CHAR_DISPLAY_WIDTH_TWO_2, ' ');
}
/** Just as {@link #testDoubleWidth()} but requires a surrogate pair. */
public void testDoubleWidthSurrogage() {
row.setChar(0, 'a', 0);
assertColumnCharIndicesStartsWith(0, 1, 2, 3, 4);
row.setChar(1, TWO_JAVA_CHARS_DISPLAY_WIDTH_TWO_2, 0);
assertColumnCharIndicesStartsWith(0, 1, 1, 3, 4);
assertLineStartsWith('a', TWO_JAVA_CHARS_DISPLAY_WIDTH_TWO_2, ' ');
row.setChar(0, TWO_JAVA_CHARS_DISPLAY_WIDTH_TWO_1, 0);
assertColumnCharIndicesStartsWith(0, 0, 2, 3, 4);
assertLineStartsWith(TWO_JAVA_CHARS_DISPLAY_WIDTH_TWO_1, ' ', ' ', ' ');
row.setChar(0, ' ', 0);
assertLineStartsWith(' ', ' ', ' ', ' ');
row.setChar(0, TWO_JAVA_CHARS_DISPLAY_WIDTH_TWO_1, 0);
row.setChar(1, TWO_JAVA_CHARS_DISPLAY_WIDTH_TWO_2, 0);
assertLineStartsWith(' ', TWO_JAVA_CHARS_DISPLAY_WIDTH_TWO_2, ' ');
row.setChar(0, 'a', 0);
assertLineStartsWith('a', TWO_JAVA_CHARS_DISPLAY_WIDTH_TWO_2, ' ');
}
public void testReplacementChar() {
row.setChar(0, TerminalEmulator.UNICODE_REPLACEMENT_CHAR, 0);
row.setChar(1, 'Y', 0);
assertLineStartsWith(TerminalEmulator.UNICODE_REPLACEMENT_CHAR, 'Y', ' ', ' ');
}
public void testSurrogateCharsWithNormalDisplayWidth() {
// These requires a UTF-16 surrogate pair, and has a display width of one.
int first = 0x1D306;
int second = 0x1D307;
// Assert the above statement:
assertEquals(2, Character.toChars(first).length);
assertEquals(2, Character.toChars(second).length);
row.setChar(0, second, 0);
assertEquals(second, Character.toCodePoint(row.mText[0], row.mText[1]));
assertEquals(' ', row.mText[2]);
assertEquals(2, row.findStartOfColumn(1));
row.setChar(0, first, 0);
assertEquals(first, Character.toCodePoint(row.mText[0], row.mText[1]));
assertEquals(' ', row.mText[2]);
assertEquals(2, row.findStartOfColumn(1));
row.setChar(1, second, 0);
row.setChar(2, 'a', 0);
assertEquals(first, Character.toCodePoint(row.mText[0], row.mText[1]));
assertEquals(second, Character.toCodePoint(row.mText[2], row.mText[3]));
assertEquals('a', row.mText[4]);
assertEquals(' ', row.mText[5]);
assertEquals(0, row.findStartOfColumn(0));
assertEquals(2, row.findStartOfColumn(1));
assertEquals(4, row.findStartOfColumn(2));
assertEquals(5, row.findStartOfColumn(3));
assertEquals(6, row.findStartOfColumn(4));
row.setChar(0, ' ', 0);
assertEquals(' ', row.mText[0]);
assertEquals(second, Character.toCodePoint(row.mText[1], row.mText[2]));
assertEquals('a', row.mText[3]);
assertEquals(' ', row.mText[4]);
assertEquals(0, row.findStartOfColumn(0));
assertEquals(1, row.findStartOfColumn(1));
assertEquals(3, row.findStartOfColumn(2));
assertEquals(4, row.findStartOfColumn(3));
assertEquals(5, row.findStartOfColumn(4));
for (int i = 0; i < 80; i++) {
row.setChar(i, i % 2 == 0 ? first : second, 0);
}
for (int i = 0; i < 80; i++) {
int idx = row.findStartOfColumn(i);
assertEquals(i % 2 == 0 ? first : second, Character.toCodePoint(row.mText[idx], row.mText[idx + 1]));
}
for (int i = 0; i < 80; i++) {
row.setChar(i, i % 2 == 0 ? 'a' : 'b', 0);
}
for (int i = 0; i < 80; i++) {
int idx = row.findStartOfColumn(i);
assertEquals(i, idx);
assertEquals(i % 2 == 0 ? 'a' : 'b', row.mText[i]);
}
}
public void testOverwritingDoubleDisplayWidthWithNormalDisplayWidth() {
// Initial "OO "
row.setChar(0, ONE_JAVA_CHAR_DISPLAY_WIDTH_TWO_1, 0);
assertEquals(ONE_JAVA_CHAR_DISPLAY_WIDTH_TWO_1, row.mText[0]);
assertEquals(' ', row.mText[1]);
assertEquals(0, row.findStartOfColumn(0));
assertEquals(0, row.findStartOfColumn(1));
assertEquals(1, row.findStartOfColumn(2));
// Setting first column to a clears second: "a "
row.setChar(0, 'a', 0);
assertEquals('a', row.mText[0]);
assertEquals(' ', row.mText[1]);
assertEquals(0, row.findStartOfColumn(0));
assertEquals(1, row.findStartOfColumn(1));
assertEquals(2, row.findStartOfColumn(2));
// Back to initial "OO "
row.setChar(0, ONE_JAVA_CHAR_DISPLAY_WIDTH_TWO_1, 0);
assertEquals(ONE_JAVA_CHAR_DISPLAY_WIDTH_TWO_1, row.mText[0]);
assertEquals(' ', row.mText[1]);
assertEquals(0, row.findStartOfColumn(0));
assertEquals(0, row.findStartOfColumn(1));
assertEquals(1, row.findStartOfColumn(2));
// Setting first column to a clears first: " a "
row.setChar(1, 'a', 0);
assertEquals(' ', row.mText[0]);
assertEquals('a', row.mText[1]);
assertEquals(' ', row.mText[2]);
assertEquals(0, row.findStartOfColumn(0));
assertEquals(1, row.findStartOfColumn(1));
assertEquals(2, row.findStartOfColumn(2));
}
public void testOverwritingDoubleDisplayWidthWithSelf() {
row.setChar(0, ONE_JAVA_CHAR_DISPLAY_WIDTH_TWO_1, 0);
row.setChar(0, ONE_JAVA_CHAR_DISPLAY_WIDTH_TWO_1, 0);
assertEquals(ONE_JAVA_CHAR_DISPLAY_WIDTH_TWO_1, row.mText[0]);
assertEquals(' ', row.mText[1]);
assertEquals(0, row.findStartOfColumn(0));
assertEquals(0, row.findStartOfColumn(1));
assertEquals(1, row.findStartOfColumn(2));
}
public void testNormalCharsWithDoubleDisplayWidth() {
// These fit in one java char, and has a display width of two.
assertTrue(ONE_JAVA_CHAR_DISPLAY_WIDTH_TWO_1 != ONE_JAVA_CHAR_DISPLAY_WIDTH_TWO_2);
assertEquals(1, Character.charCount(ONE_JAVA_CHAR_DISPLAY_WIDTH_TWO_1));
assertEquals(1, Character.charCount(ONE_JAVA_CHAR_DISPLAY_WIDTH_TWO_2));
assertEquals(2, WcWidth.width(ONE_JAVA_CHAR_DISPLAY_WIDTH_TWO_1));
assertEquals(2, WcWidth.width(ONE_JAVA_CHAR_DISPLAY_WIDTH_TWO_2));
row.setChar(0, ONE_JAVA_CHAR_DISPLAY_WIDTH_TWO_1, 0);
assertEquals(ONE_JAVA_CHAR_DISPLAY_WIDTH_TWO_1, row.mText[0]);
assertEquals(0, row.findStartOfColumn(1));
assertEquals(' ', row.mText[1]);
row.setChar(0, 'a', 0);
assertEquals('a', row.mText[0]);
assertEquals(' ', row.mText[1]);
assertEquals(1, row.findStartOfColumn(1));
row.setChar(0, ONE_JAVA_CHAR_DISPLAY_WIDTH_TWO_1, 0);
assertEquals(ONE_JAVA_CHAR_DISPLAY_WIDTH_TWO_1, row.mText[0]);
// The first character fills both first columns.
assertEquals(0, row.findStartOfColumn(1));
row.setChar(2, 'a', 0);
assertEquals(ONE_JAVA_CHAR_DISPLAY_WIDTH_TWO_1, row.mText[0]);
assertEquals('a', row.mText[1]);
assertEquals(1, row.findStartOfColumn(2));
row.setChar(0, 'c', 0);
assertEquals('c', row.mText[0]);
assertEquals(' ', row.mText[1]);
assertEquals('a', row.mText[2]);
assertEquals(' ', row.mText[3]);
assertEquals(0, row.findStartOfColumn(0));
assertEquals(1, row.findStartOfColumn(1));
assertEquals(2, row.findStartOfColumn(2));
}
public void testNormalCharsWithDoubleDisplayWidthOverlapping() {
// These fit in one java char, and has a display width of two.
row.setChar(0, ONE_JAVA_CHAR_DISPLAY_WIDTH_TWO_1, 0);
row.setChar(2, ONE_JAVA_CHAR_DISPLAY_WIDTH_TWO_2, 0);
row.setChar(4, 'a', 0);
// O = ONE_JAVA_CHAR_DISPLAY_WIDTH_TWO
// A = ANOTHER_JAVA_CHAR_DISPLAY_WIDTH_TWO
// "OOAAa "
assertEquals(0, row.findStartOfColumn(0));
assertEquals(0, row.findStartOfColumn(1));
assertEquals(1, row.findStartOfColumn(2));
assertEquals(1, row.findStartOfColumn(3));
assertEquals(2, row.findStartOfColumn(4));
assertEquals(ONE_JAVA_CHAR_DISPLAY_WIDTH_TWO_1, row.mText[0]);
assertEquals(ONE_JAVA_CHAR_DISPLAY_WIDTH_TWO_2, row.mText[1]);
assertEquals('a', row.mText[2]);
assertEquals(' ', row.mText[3]);
row.setChar(1, ONE_JAVA_CHAR_DISPLAY_WIDTH_TWO_2, 0);
// " AA a "
assertEquals(' ', row.mText[0]);
assertEquals(ONE_JAVA_CHAR_DISPLAY_WIDTH_TWO_2, row.mText[1]);
assertEquals(' ', row.mText[2]);
assertEquals('a', row.mText[3]);
assertEquals(' ', row.mText[4]);
assertEquals(0, row.findStartOfColumn(0));
assertEquals(1, row.findStartOfColumn(1));
assertEquals(1, row.findStartOfColumn(2));
assertEquals(2, row.findStartOfColumn(3));
assertEquals(3, row.findStartOfColumn(4));
}
// https://github.com/jackpal/Android-Terminal-Emulator/issues/145
public void testCrashATE145() {
// 0xC2541 is unassigned, use display width 1 for UNICODE_REPLACEMENT_CHAR.
// assertEquals(1, WcWidth.width(0xC2541));
assertEquals(2, Character.charCount(0xC2541));
assertEquals(2, WcWidth.width(0x73EE));
assertEquals(1, Character.charCount(0x73EE));
assertEquals(0, WcWidth.width(0x009F));
assertEquals(1, Character.charCount(0x009F));
int[] points = new int[]{0xC2541, 'a', '8', 0x73EE, 0x009F, 0x881F, 0x8324, 0xD4C9, 0xFFFD, 'B', 0x009B, 0x61C9, 'Z'};
// int[] expected = new int[] { TerminalEmulator.UNICODE_REPLACEMENT_CHAR, 'a', '8', 0x73EE, 0x009F, 0x881F, 0x8324, 0xD4C9, 0xFFFD,
// 'B', 0x009B, 0x61C9, 'Z' };
int currentColumn = 0;
for (int point : points) {
row.setChar(currentColumn, point, 0);
currentColumn += WcWidth.width(point);
}
// assertLineStartsWith(points);
// assertEquals(Character.highSurrogate(0xC2541), line.mText[0]);
// assertEquals(Character.lowSurrogate(0xC2541), line.mText[1]);
// assertEquals('a', line.mText[2]);
// assertEquals('8', line.mText[3]);
// assertEquals(Character.highSurrogate(0x73EE), line.mText[4]);
// assertEquals(Character.lowSurrogate(0x73EE), line.mText[5]);
//
// char[] chars = line.mText;
// int charIndex = 0;
// for (int i = 0; i < points.length; i++) {
// char c = chars[charIndex];
// charIndex++;
// int thisPoint = (int) c;
// if (Character.isHighSurrogate(c)) {
// thisPoint = Character.toCodePoint(c, chars[charIndex]);
// charIndex++;
// }
// assertEquals("At index=" + i + ", charIndex=" + charIndex + ", char=" + (char) thisPoint, points[i], thisPoint);
// }
}
public void testNormalization() {
// int lowerCaseN = 0x006E;
// int combiningTilde = 0x0303;
// int combined = 0x00F1;
row.setChar(0, 0x006E, 0);
assertEquals(80, row.getSpaceUsed());
row.setChar(0, 0x0303, 0);
assertEquals(81, row.getSpaceUsed());
// assertEquals("\u00F1 ", new String(term.getScreen().getLine(0)));
assertLineStartsWith(0x006E, 0x0303, ' ');
}
public void testInsertWideAtLastColumn() {
row.setChar(COLUMNS - 2, 'Z', 0);
row.setChar(COLUMNS - 1, 'a', 0);
assertEquals('Z', row.mText[row.findStartOfColumn(COLUMNS - 2)]);
assertEquals('a', row.mText[row.findStartOfColumn(COLUMNS - 1)]);
row.setChar(COLUMNS - 1, 'ö', 0);
assertEquals('Z', row.mText[row.findStartOfColumn(COLUMNS - 2)]);
assertEquals('ö', row.mText[row.findStartOfColumn(COLUMNS - 1)]);
// line.setChar(COLUMNS - 1, ONE_JAVA_CHAR_DISPLAY_WIDTH_TWO_1);
// assertEquals('Z', line.mText[line.findStartOfColumn(COLUMNS - 2)]);
// assertEquals(' ', line.mText[line.findStartOfColumn(COLUMNS - 1)]);
}
}

View File

@@ -1,289 +0,0 @@
package com.termux.terminal;
import java.io.UnsupportedEncodingException;
public class TerminalTest extends TerminalTestCase {
public void testCursorPositioning() throws Exception {
withTerminalSized(10, 10).placeCursorAndAssert(1, 2).placeCursorAndAssert(3, 5).placeCursorAndAssert(2, 2).enterString("A")
.assertCursorAt(2, 3);
}
public void testScreen() throws UnsupportedEncodingException {
withTerminalSized(3, 3);
assertLinesAre(" ", " ", " ");
assertEquals("", mTerminal.getScreen().getTranscriptText());
enterString("hi").assertLinesAre("hi ", " ", " ");
assertEquals("hi", mTerminal.getScreen().getTranscriptText());
enterString("\r\nu");
assertEquals("hi\nu", mTerminal.getScreen().getTranscriptText());
mTerminal.reset();
assertEquals("hi\nu", mTerminal.getScreen().getTranscriptText());
withTerminalSized(3, 3).enterString("hello");
assertEquals("hello", mTerminal.getScreen().getTranscriptText());
enterString("\r\nworld");
assertEquals("hello\nworld", mTerminal.getScreen().getTranscriptText());
}
public void testScrollDownInAltBuffer() {
withTerminalSized(3, 3).enterString("\033[?1049h");
enterString("\033[38;5;111m1\r\n");
enterString("\033[38;5;112m2\r\n");
enterString("\033[38;5;113m3\r\n");
enterString("\033[38;5;114m4\r\n");
enterString("\033[38;5;115m5");
assertLinesAre("3 ", "4 ", "5 ");
assertForegroundColorAt(0, 0, 113);
assertForegroundColorAt(1, 0, 114);
assertForegroundColorAt(2, 0, 115);
}
public void testMouseClick() throws Exception {
withTerminalSized(10, 10);
assertFalse(mTerminal.isMouseTrackingActive());
enterString("\033[?1000h");
assertTrue(mTerminal.isMouseTrackingActive());
enterString("\033[?1000l");
assertFalse(mTerminal.isMouseTrackingActive());
enterString("\033[?1000h");
assertTrue(mTerminal.isMouseTrackingActive());
enterString("\033[?1006h");
mTerminal.sendMouseEvent(TerminalEmulator.MOUSE_LEFT_BUTTON, 3, 4, true);
assertEquals("\033[<0;3;4M", mOutput.getOutputAndClear());
mTerminal.sendMouseEvent(TerminalEmulator.MOUSE_LEFT_BUTTON, 3, 4, false);
assertEquals("\033[<0;3;4m", mOutput.getOutputAndClear());
}
public void testNormalization() throws UnsupportedEncodingException {
// int lowerCaseN = 0x006E;
// int combiningTilde = 0x0303;
// int combined = 0x00F1;
withTerminalSized(3, 3).assertLinesAre(" ", " ", " ");
enterString("\u006E\u0303");
assertEquals(1, WcWidth.width("\u006E\u0303".toCharArray(), 0));
// assertEquals("\u00F1 ", new String(mTerminal.getScreen().getLine(0)));
assertLinesAre("\u006E\u0303 ", " ", " ");
}
/** On "\e[18t" xterm replies with "\e[8;${HEIGHT};${WIDTH}t" */
public void testReportTerminalSize() throws Exception {
withTerminalSized(5, 5);
assertEnteringStringGivesResponse("\033[18t", "\033[8;5;5t");
for (int width = 3; width < 12; width++) {
for (int height = 3; height < 12; height++) {
mTerminal.resize(width, height);
assertEnteringStringGivesResponse("\033[18t", "\033[8;" + height + ";" + width + "t");
}
}
}
/** Device Status Report (DSR) and Report Cursor Position (CPR). */
public void testDeviceStatusReport() throws Exception {
withTerminalSized(5, 5);
assertEnteringStringGivesResponse("\033[5n", "\033[0n");
assertEnteringStringGivesResponse("\033[6n", "\033[1;1R");
enterString("AB");
assertEnteringStringGivesResponse("\033[6n", "\033[1;3R");
enterString("\r\n");
assertEnteringStringGivesResponse("\033[6n", "\033[2;1R");
}
/** Test the cursor shape changes using DECSCUSR. */
public void testSetCursorStyle() throws Exception {
withTerminalSized(5, 5);
assertEquals(TerminalEmulator.CURSOR_STYLE_BLOCK, mTerminal.getCursorStyle());
enterString("\033[3 q");
assertEquals(TerminalEmulator.CURSOR_STYLE_UNDERLINE, mTerminal.getCursorStyle());
enterString("\033[5 q");
assertEquals(TerminalEmulator.CURSOR_STYLE_BAR, mTerminal.getCursorStyle());
enterString("\033[0 q");
assertEquals(TerminalEmulator.CURSOR_STYLE_BLOCK, mTerminal.getCursorStyle());
enterString("\033[6 q");
assertEquals(TerminalEmulator.CURSOR_STYLE_BAR, mTerminal.getCursorStyle());
enterString("\033[4 q");
assertEquals(TerminalEmulator.CURSOR_STYLE_UNDERLINE, mTerminal.getCursorStyle());
enterString("\033[1 q");
assertEquals(TerminalEmulator.CURSOR_STYLE_BLOCK, mTerminal.getCursorStyle());
enterString("\033[4 q");
assertEquals(TerminalEmulator.CURSOR_STYLE_UNDERLINE, mTerminal.getCursorStyle());
enterString("\033[2 q");
assertEquals(TerminalEmulator.CURSOR_STYLE_BLOCK, mTerminal.getCursorStyle());
}
public void testPaste() {
withTerminalSized(5, 5);
mTerminal.paste("hi");
assertEquals("hi", mOutput.getOutputAndClear());
enterString("\033[?2004h");
mTerminal.paste("hi");
assertEquals("\033[200~" + "hi" + "\033[201~", mOutput.getOutputAndClear());
enterString("\033[?2004l");
mTerminal.paste("hi");
assertEquals("hi", mOutput.getOutputAndClear());
}
public void testSelectGraphics() {
withTerminalSized(5, 5);
enterString("\033[31m");
assertEquals(mTerminal.mForeColor, 1);
enterString("\033[32m");
assertEquals(mTerminal.mForeColor, 2);
enterString("\033[43m");
assertEquals(2, mTerminal.mForeColor);
assertEquals(3, mTerminal.mBackColor);
// SGR 0 should reset both foreground and background color.
enterString("\033[0m");
assertEquals(TextStyle.COLOR_INDEX_FOREGROUND, mTerminal.mForeColor);
assertEquals(TextStyle.COLOR_INDEX_BACKGROUND, mTerminal.mBackColor);
// 256 colors:
enterString("\033[38;5;119m");
assertEquals(119, mTerminal.mForeColor);
assertEquals(TextStyle.COLOR_INDEX_BACKGROUND, mTerminal.mBackColor);
enterString("\033[48;5;129m");
assertEquals(119, mTerminal.mForeColor);
assertEquals(129, mTerminal.mBackColor);
// Invalid parameter:
enterString("\033[48;8;129m");
assertEquals(119, mTerminal.mForeColor);
assertEquals(129, mTerminal.mBackColor);
// Multiple parameters at once:
enterString("\033[38;5;178;48;5;179;m");
assertEquals(178, mTerminal.mForeColor);
assertEquals(179, mTerminal.mBackColor);
// 24 bit colors:
enterString(("\033[0m")); // Reset fg and bg colors.
enterString("\033[38;2;255;127;2m");
int expectedForeground = 0xff000000 | (255 << 16) | (127 << 8) | 2;
assertEquals(expectedForeground, mTerminal.mForeColor);
assertEquals(TextStyle.COLOR_INDEX_BACKGROUND, mTerminal.mBackColor);
enterString("\033[48;2;1;2;254m");
int expectedBackground = 0xff000000 | (1 << 16) | (2 << 8) | 254;
assertEquals(expectedForeground, mTerminal.mForeColor);
assertEquals(expectedBackground, mTerminal.mBackColor);
// 24 bit colors, set fg and bg at once:
enterString(("\033[0m")); // Reset fg and bg colors.
assertEquals(TextStyle.COLOR_INDEX_FOREGROUND, mTerminal.mForeColor);
assertEquals(TextStyle.COLOR_INDEX_BACKGROUND, mTerminal.mBackColor);
enterString("\033[38;2;255;127;2;48;2;1;2;254m");
assertEquals(expectedForeground, mTerminal.mForeColor);
assertEquals(expectedBackground, mTerminal.mBackColor);
// 24 bit colors, invalid input:
enterString("\033[38;2;300;127;2;48;2;1;300;254m");
assertEquals(expectedForeground, mTerminal.mForeColor);
assertEquals(expectedBackground, mTerminal.mBackColor);
}
public void testBackgroundColorErase() {
final int rows = 3;
final int cols = 3;
withTerminalSized(cols, rows);
for (int r = 0; r < rows; r++) {
for (int c = 0; c < cols; c++) {
long style = getStyleAt(r, c);
assertEquals(TextStyle.COLOR_INDEX_FOREGROUND, TextStyle.decodeForeColor(style));
assertEquals(TextStyle.COLOR_INDEX_BACKGROUND, TextStyle.decodeBackColor(style));
}
}
// Foreground color to 119:
enterString("\033[38;5;119m");
// Background color to 129:
enterString("\033[48;5;129m");
// Clear with ED, Erase in Display:
enterString("\033[2J");
for (int r = 0; r < rows; r++) {
for (int c = 0; c < cols; c++) {
long style = getStyleAt(r, c);
assertEquals(119, TextStyle.decodeForeColor(style));
assertEquals(129, TextStyle.decodeBackColor(style));
}
}
// Background color to 139:
enterString("\033[48;5;139m");
// Insert two blank lines.
enterString("\033[2L");
for (int r = 0; r < rows; r++) {
for (int c = 0; c < cols; c++) {
long style = getStyleAt(r, c);
assertEquals((r == 0 || r == 1) ? 139 : 129, TextStyle.decodeBackColor(style));
}
}
withTerminalSized(cols, rows);
// Background color to 129:
enterString("\033[48;5;129m");
// Erase two characters, filling them with background color:
enterString("\033[2X");
assertEquals(129, TextStyle.decodeBackColor(getStyleAt(0, 0)));
assertEquals(129, TextStyle.decodeBackColor(getStyleAt(0, 1)));
assertEquals(TextStyle.COLOR_INDEX_BACKGROUND, TextStyle.decodeBackColor(getStyleAt(0, 2)));
}
public void testParseColor() {
assertEquals(0xFF0000FA, TerminalColors.parse("#0000FA"));
assertEquals(0xFF000000, TerminalColors.parse("#000000"));
assertEquals(0xFF000000, TerminalColors.parse("#000"));
assertEquals(0xFF000000, TerminalColors.parse("#000000000"));
assertEquals(0xFF53186f, TerminalColors.parse("#53186f"));
assertEquals(0xFFFF00FF, TerminalColors.parse("rgb:F/0/F"));
assertEquals(0xFF0000FA, TerminalColors.parse("rgb:00/00/FA"));
assertEquals(0xFF53186f, TerminalColors.parse("rgb:53/18/6f"));
assertEquals(0, TerminalColors.parse("invalid_0000FA"));
assertEquals(0, TerminalColors.parse("#3456"));
}
/** The ncurses library still uses this. */
public void testLineDrawing() {
// 016 - shift out / G1. 017 - shift in / G0. "ESC ) 0" - use line drawing for G1
withTerminalSized(4, 2).enterString("q\033)0q\016q\017q").assertLinesAre("qq─q", " ");
// "\0337", saving cursor should save G0, G1 and invoked charset and "ESC 8" should restore.
withTerminalSized(4, 2).enterString("\033)0\016qqq\0337\017\0338q").assertLinesAre("────", " ");
}
public void testSoftTerminalReset() {
// See http://vt100.net/docs/vt510-rm/DECSTR and https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=650304
// "\033[?7l" is DECRST to disable wrap-around, and DECSTR ("\033[!p") should reset it.
withTerminalSized(3, 3).enterString("\033[?7lABCD").assertLinesAre("ABD", " ", " ");
enterString("\033[!pEF").assertLinesAre("ABE", "F ", " ");
}
public void testBel() {
withTerminalSized(3, 3);
assertEquals(0, mOutput.bellsRung);
enterString("\07");
assertEquals(1, mOutput.bellsRung);
enterString("hello\07");
assertEquals(2, mOutput.bellsRung);
enterString("\07hello");
assertEquals(3, mOutput.bellsRung);
enterString("hello\07world");
assertEquals(4, mOutput.bellsRung);
}
public void testAutomargins() throws UnsupportedEncodingException {
withTerminalSized(3, 3).enterString("abc").assertLinesAre("abc", " ", " ").assertCursorAt(0, 2);
enterString("d").assertLinesAre("abc", "d ", " ").assertCursorAt(1, 1);
withTerminalSized(3, 3).enterString("abc\r ").assertLinesAre(" bc", " ", " ").assertCursorAt(0, 1);
}
public void testTab() {
withTerminalSized(11, 2).enterString("01234567890\r\tXX").assertLinesAre("01234567XX0", " ");
withTerminalSized(11, 2).enterString("01234567890\033[44m\r\tXX").assertLinesAre("01234567XX0", " ");
}
}

View File

@@ -1,310 +0,0 @@
package com.termux.terminal;
import junit.framework.AssertionFailedError;
import junit.framework.TestCase;
import java.io.ByteArrayOutputStream;
import java.io.UnsupportedEncodingException;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Objects;
import java.util.Set;
public abstract class TerminalTestCase extends TestCase {
public static class MockTerminalOutput extends TerminalOutput {
final ByteArrayOutputStream baos = new ByteArrayOutputStream();
public final List<ChangedTitle> titleChanges = new ArrayList<>();
public final List<String> clipboardPuts = new ArrayList<>();
public int bellsRung = 0;
public int colorsChanged = 0;
@Override
public void write(byte[] data, int offset, int count) {
baos.write(data, offset, count);
}
public String getOutputAndClear() {
try {
String result = new String(baos.toByteArray(), "UTF-8");
baos.reset();
return result;
} catch (UnsupportedEncodingException e) {
throw new RuntimeException(e);
}
}
@Override
public void titleChanged(String oldTitle, String newTitle) {
titleChanges.add(new ChangedTitle(oldTitle, newTitle));
}
@Override
public void clipboardText(String text) {
clipboardPuts.add(text);
}
@Override
public void onBell() {
bellsRung++;
}
@Override
public void onColorsChanged() {
colorsChanged++;
}
}
public TerminalEmulator mTerminal;
public MockTerminalOutput mOutput;
public static final class ChangedTitle {
final String oldTitle;
final String newTitle;
public ChangedTitle(String oldTitle, String newTitle) {
this.oldTitle = oldTitle;
this.newTitle = newTitle;
}
@Override
public boolean equals(Object o) {
if (!(o instanceof ChangedTitle)) return false;
ChangedTitle other = (ChangedTitle) o;
return Objects.equals(oldTitle, other.oldTitle) && Objects.equals(newTitle, other.newTitle);
}
@Override
public int hashCode() {
return Objects.hash(oldTitle, newTitle);
}
@Override
public String toString() {
return "ChangedTitle[oldTitle=" + oldTitle + ", newTitle=" + newTitle + "]";
}
}
public TerminalTestCase enterString(String s) {
byte[] bytes = s.getBytes(StandardCharsets.UTF_8);
mTerminal.append(bytes, bytes.length);
assertInvariants();
return this;
}
public void assertEnteringStringGivesResponse(String input, String expectedResponse) {
enterString(input);
String response = mOutput.getOutputAndClear();
assertEquals(expectedResponse, response);
}
@Override
protected void setUp() throws Exception {
mOutput = new MockTerminalOutput();
}
protected TerminalTestCase withTerminalSized(int columns, int rows) {
mTerminal = new TerminalEmulator(mOutput, columns, rows, rows * 2);
return this;
}
public void assertHistoryStartsWith(String... rows) {
assertTrue("About to check " + rows.length + " lines, but only " + mTerminal.getScreen().getActiveTranscriptRows() + " in history",
mTerminal.getScreen().getActiveTranscriptRows() >= rows.length);
for (int i = 0; i < rows.length; i++) {
assertLineIs(-i - 1, rows[i]);
}
}
private static final class LineWrapper {
final TerminalRow mLine;
public LineWrapper(TerminalRow line) {
mLine = line;
}
@Override
public int hashCode() {
return System.identityHashCode(mLine);
}
@Override
public boolean equals(Object o) {
return o instanceof LineWrapper && ((LineWrapper) o).mLine == mLine;
}
}
protected TerminalTestCase assertInvariants() {
TerminalBuffer screen = mTerminal.getScreen();
TerminalRow[] lines = screen.mLines;
Set<LineWrapper> linesSet = new HashSet<>();
for (int i = 0; i < lines.length; i++) {
if (lines[i] == null) continue;
assertTrue("Line exists at multiple places: " + i, linesSet.add(new LineWrapper(lines[i])));
char[] text = lines[i].mText;
int usedChars = lines[i].getSpaceUsed();
int currentColumn = 0;
for (int j = 0; j < usedChars; j++) {
char c = text[j];
int codePoint;
if (Character.isHighSurrogate(c)) {
char lowSurrogate = text[++j];
assertTrue("High surrogate without following low surrogate", Character.isLowSurrogate(lowSurrogate));
codePoint = Character.toCodePoint(c, lowSurrogate);
} else {
assertFalse("Low surrogate without preceding high surrogate", Character.isLowSurrogate(c));
codePoint = c;
}
assertFalse("Screen should never contain unassigned characters", Character.getType(codePoint) == Character.UNASSIGNED);
int width = WcWidth.width(codePoint);
assertFalse("The first column should not start with combining character", currentColumn == 0 && width < 0);
if (width > 0) currentColumn += width;
}
assertEquals("Line whose width does not match screens. line=" + new String(lines[i].mText, 0, lines[i].getSpaceUsed()),
screen.mColumns, currentColumn);
}
assertEquals("The alt buffer should have have no history", mTerminal.mAltBuffer.mTotalRows, mTerminal.mAltBuffer.mScreenRows);
if (mTerminal.isAlternateBufferActive()) {
assertEquals("The alt buffer should be the same size as the screen", mTerminal.mRows, mTerminal.mAltBuffer.mTotalRows);
}
return this;
}
protected void assertLineIs(int line, String expected) {
TerminalRow l = mTerminal.getScreen().allocateFullLineIfNecessary(mTerminal.getScreen().externalToInternalRow(line));
char[] chars = l.mText;
int textLen = l.getSpaceUsed();
if (textLen != expected.length()) fail("Expected '" + expected + "' (len=" + expected.length() + "), was='"
+ new String(chars, 0, textLen) + "' (len=" + textLen + ")");
for (int i = 0; i < textLen; i++) {
if (expected.charAt(i) != chars[i])
fail("Expected '" + expected + "', was='" + new String(chars, 0, textLen) + "' - first different at index=" + i);
}
}
public TerminalTestCase assertLinesAre(String... lines) {
assertEquals(lines.length, mTerminal.getScreen().mScreenRows);
for (int i = 0; i < lines.length; i++)
try {
assertLineIs(i, lines[i]);
} catch (AssertionFailedError e) {
throw new AssertionFailedError("Line: " + i + " - " + e.getMessage());
}
return this;
}
public TerminalTestCase resize(int cols, int rows) {
mTerminal.resize(cols, rows);
assertInvariants();
return this;
}
public TerminalTestCase assertLineWraps(boolean... lines) {
for (int i = 0; i < lines.length; i++)
assertEquals("line=" + i, lines[i], mTerminal.getScreen().mLines[mTerminal.getScreen().externalToInternalRow(i)].mLineWrap);
return this;
}
protected TerminalTestCase assertLineStartsWith(int line, int... codePoints) {
char[] chars = mTerminal.getScreen().mLines[mTerminal.getScreen().externalToInternalRow(line)].mText;
int charIndex = 0;
for (int i = 0; i < codePoints.length; i++) {
int lineCodePoint = chars[charIndex++];
if (Character.isHighSurrogate((char) lineCodePoint)) {
lineCodePoint = Character.toCodePoint((char) lineCodePoint, chars[charIndex++]);
}
assertEquals("Differing a code point index=" + i, codePoints[i], lineCodePoint);
}
return this;
}
protected TerminalTestCase placeCursorAndAssert(int row, int col) {
// +1 due to escape sequence being one based.
enterString("\033[" + (row + 1) + ";" + (col + 1) + "H");
assertCursorAt(row, col);
return this;
}
public TerminalTestCase assertCursorAt(int row, int col) {
int actualRow = mTerminal.getCursorRow();
int actualCol = mTerminal.getCursorCol();
if (!(row == actualRow && col == actualCol))
fail("Expected cursor at (row,col)=(" + row + ", " + col + ") but was (" + actualRow + ", " + actualCol + ")");
return this;
}
/** For testing only. Encoded style according to {@link TextStyle}. */
public long getStyleAt(int externalRow, int column) {
return mTerminal.getScreen().getStyleAt(externalRow, column);
}
public static class EffectLine {
final int[] styles;
public EffectLine(int[] styles) {
this.styles = styles;
}
}
protected EffectLine effectLine(int... bits) {
return new EffectLine(bits);
}
public TerminalTestCase assertEffectAttributesSet(EffectLine... lines) {
assertEquals(lines.length, mTerminal.getScreen().mScreenRows);
for (int i = 0; i < lines.length; i++) {
int[] line = lines[i].styles;
for (int j = 0; j < line.length; j++) {
int effectsAtCell = TextStyle.decodeEffect(getStyleAt(i, j));
int attributes = line[j];
if ((effectsAtCell & attributes) != attributes) fail("Line=" + i + ", column=" + j + ", expected "
+ describeStyle(attributes) + " set, was " + describeStyle(effectsAtCell));
}
}
return this;
}
public TerminalTestCase assertForegroundIndices(EffectLine... lines) {
assertEquals(lines.length, mTerminal.getScreen().mScreenRows);
for (int i = 0; i < lines.length; i++) {
int[] line = lines[i].styles;
for (int j = 0; j < line.length; j++) {
int actualColor = TextStyle.decodeForeColor(getStyleAt(i, j));
int expectedColor = line[j];
if (actualColor != expectedColor) fail("Line=" + i + ", column=" + j + ", expected color "
+ Integer.toHexString(expectedColor) + " set, was " + Integer.toHexString(actualColor));
}
}
return this;
}
private static String describeStyle(int styleBits) {
return "'" + ((styleBits & TextStyle.CHARACTER_ATTRIBUTE_BLINK) != 0 ? ":BLINK:" : "")
+ ((styleBits & TextStyle.CHARACTER_ATTRIBUTE_BOLD) != 0 ? ":BOLD:" : "")
+ ((styleBits & TextStyle.CHARACTER_ATTRIBUTE_INVERSE) != 0 ? ":INVERSE:" : "")
+ ((styleBits & TextStyle.CHARACTER_ATTRIBUTE_INVISIBLE) != 0 ? ":INVISIBLE:" : "")
+ ((styleBits & TextStyle.CHARACTER_ATTRIBUTE_ITALIC) != 0 ? ":ITALIC:" : "")
+ ((styleBits & TextStyle.CHARACTER_ATTRIBUTE_PROTECTED) != 0 ? ":PROTECTED:" : "")
+ ((styleBits & TextStyle.CHARACTER_ATTRIBUTE_STRIKETHROUGH) != 0 ? ":STRIKETHROUGH:" : "")
+ ((styleBits & TextStyle.CHARACTER_ATTRIBUTE_UNDERLINE) != 0 ? ":UNDERLINE:" : "") + "'";
}
public void assertForegroundColorAt(int externalRow, int column, int color) {
long style = mTerminal.getScreen().mLines[mTerminal.getScreen().externalToInternalRow(externalRow)].getStyle(column);
assertEquals(color, TextStyle.decodeForeColor(style));
}
public TerminalTestCase assertColor(int colorIndex, int expected) {
int actual = mTerminal.mColors.mCurrentColors[colorIndex];
if (expected != actual) {
fail("Color index=" + colorIndex + ", expected=" + Integer.toHexString(expected) + ", was=" + Integer.toHexString(actual));
}
return this;
}
}

View File

@@ -1,65 +0,0 @@
package com.termux.terminal;
import junit.framework.TestCase;
public class TextStyleTest extends TestCase {
private static final int[] ALL_EFFECTS = new int[]{0, TextStyle.CHARACTER_ATTRIBUTE_BOLD, TextStyle.CHARACTER_ATTRIBUTE_ITALIC,
TextStyle.CHARACTER_ATTRIBUTE_UNDERLINE, TextStyle.CHARACTER_ATTRIBUTE_BLINK, TextStyle.CHARACTER_ATTRIBUTE_INVERSE,
TextStyle.CHARACTER_ATTRIBUTE_INVISIBLE, TextStyle.CHARACTER_ATTRIBUTE_STRIKETHROUGH, TextStyle.CHARACTER_ATTRIBUTE_PROTECTED,
TextStyle.CHARACTER_ATTRIBUTE_DIM};
public void testEncodingSingle() {
for (int fx : ALL_EFFECTS) {
for (int fg = 0; fg < TextStyle.NUM_INDEXED_COLORS; fg++) {
for (int bg = 0; bg < TextStyle.NUM_INDEXED_COLORS; bg++) {
long encoded = TextStyle.encode(fg, bg, fx);
assertEquals(fg, TextStyle.decodeForeColor(encoded));
assertEquals(bg, TextStyle.decodeBackColor(encoded));
assertEquals(fx, TextStyle.decodeEffect(encoded));
}
}
}
}
public void testEncoding24Bit() {
int[] values = {255, 240, 127, 1, 0};
for (int red : values) {
for (int green : values) {
for (int blue : values) {
int argb = 0xFF000000 | (red << 16) | (green << 8) | blue;
long encoded = TextStyle.encode(argb, 0, 0);
assertEquals(argb, TextStyle.decodeForeColor(encoded));
encoded = TextStyle.encode(0, argb, 0);
assertEquals(argb, TextStyle.decodeBackColor(encoded));
}
}
}
}
public void testEncodingCombinations() {
for (int f1 : ALL_EFFECTS) {
for (int f2 : ALL_EFFECTS) {
int combined = f1 | f2;
assertEquals(combined, TextStyle.decodeEffect(TextStyle.encode(0, 0, combined)));
}
}
}
public void testEncodingStrikeThrough() {
long encoded = TextStyle.encode(TextStyle.COLOR_INDEX_FOREGROUND, TextStyle.COLOR_INDEX_BACKGROUND,
TextStyle.CHARACTER_ATTRIBUTE_STRIKETHROUGH);
assertTrue((TextStyle.decodeEffect(encoded) & TextStyle.CHARACTER_ATTRIBUTE_STRIKETHROUGH) != 0);
}
public void testEncodingProtected() {
long encoded = TextStyle.encode(TextStyle.COLOR_INDEX_FOREGROUND, TextStyle.COLOR_INDEX_BACKGROUND,
TextStyle.CHARACTER_ATTRIBUTE_STRIKETHROUGH);
assertTrue((TextStyle.decodeEffect(encoded) & TextStyle.CHARACTER_ATTRIBUTE_PROTECTED) == 0);
encoded = TextStyle.encode(TextStyle.COLOR_INDEX_FOREGROUND, TextStyle.COLOR_INDEX_BACKGROUND,
TextStyle.CHARACTER_ATTRIBUTE_STRIKETHROUGH | TextStyle.CHARACTER_ATTRIBUTE_PROTECTED);
assertTrue((TextStyle.decodeEffect(encoded) & TextStyle.CHARACTER_ATTRIBUTE_PROTECTED) != 0);
}
}

View File

@@ -1,136 +0,0 @@
package com.termux.terminal;
import java.io.UnsupportedEncodingException;
public class UnicodeInputTest extends TerminalTestCase {
public void testIllFormedUtf8SuccessorByteNotConsumed() throws Exception {
// The Unicode Standard Version 6.2 Core Specification (http://www.unicode.org/versions/Unicode6.2.0/ch03.pdf):
// "If the converter encounters an ill-formed UTF-8 code unit sequence which starts with a valid first byte, but which does not
// continue with valid successor bytes (see Table 3-7), it must not consume the successor bytes as part of the ill-formed
// subsequence whenever those successor bytes themselves constitute part of a well-formed UTF-8 code unit subsequence."
withTerminalSized(5, 5);
mTerminal.append(new byte[]{(byte) 0b11101111, (byte) 'a'}, 2);
assertLineIs(0, ((char) TerminalEmulator.UNICODE_REPLACEMENT_CHAR) + "a ");
// https://code.google.com/p/chromium/issues/detail?id=212704
byte[] input = new byte[]{
(byte) 0x61, (byte) 0xF1,
(byte) 0x80, (byte) 0x80,
(byte) 0xe1, (byte) 0x80,
(byte) 0xc2, (byte) 0x62,
(byte) 0x80, (byte) 0x63,
(byte) 0x80, (byte) 0xbf,
(byte) 0x64
};
withTerminalSized(10, 2);
mTerminal.append(input, input.length);
assertLinesAre("a\uFFFD\uFFFD\uFFFDb\uFFFDc\uFFFD\uFFFDd", " ");
// Surrogate pairs.
withTerminalSized(5, 2);
input = new byte[]{
(byte) 0xed, (byte) 0xa0,
(byte) 0x80, (byte) 0xed,
(byte) 0xad, (byte) 0xbf,
(byte) 0xed, (byte) 0xae,
(byte) 0x80, (byte) 0xed,
(byte) 0xbf, (byte) 0xbf
};
mTerminal.append(input, input.length);
assertLinesAre("\uFFFD\uFFFD\uFFFD\uFFFD ", " ");
// https://bugzilla.mozilla.org/show_bug.cgi?id=746900: "with this patch 0xe0 0x80 is decoded as two U+FFFDs,
// but 0xe0 0xa0 is decoded as a single U+FFFD, and this is correct according to the "Best Practices", but IE
// and Chrome (Version 22.0.1229.94) decode both of them as two U+FFFDs. Opera 12.11 decodes both of them as
// one U+FFFD".
withTerminalSized(5, 2);
input = new byte[]{(byte) 0xe0, (byte) 0xa0, ' '};
mTerminal.append(input, input.length);
assertLinesAre("\uFFFD ", " ");
// withTerminalSized(5, 2);
// input = new byte[]{(byte) 0xe0, (byte) 0x80, 'a'};
// mTerminal.append(input, input.length);
// assertLinesAre("\uFFFD\uFFFDa ", " ");
}
public void testUnassignedCodePoint() throws UnsupportedEncodingException {
withTerminalSized(3, 3);
// UTF-8 for U+C2541, an unassigned code point:
byte[] b = new byte[]{(byte) 0xf3, (byte) 0x82, (byte) 0x95, (byte) 0x81};
mTerminal.append(b, b.length);
enterString("Y");
assertEquals(1, Character.charCount(TerminalEmulator.UNICODE_REPLACEMENT_CHAR));
assertLineStartsWith(0, TerminalEmulator.UNICODE_REPLACEMENT_CHAR, (int) 'Y', ' ');
}
public void testStuff() {
withTerminalSized(80, 24);
byte[] b = new byte[]{(byte) 0xf3, (byte) 0x82, (byte) 0x95, (byte) 0x81, (byte) 0x61, (byte) 0x38, (byte) 0xe7, (byte) 0x8f,
(byte) 0xae, (byte) 0xc2, (byte) 0x9f, (byte) 0xe8, (byte) 0xa0, (byte) 0x9f, (byte) 0xe8, (byte) 0x8c, (byte) 0xa4,
(byte) 0xed, (byte) 0x93, (byte) 0x89, (byte) 0xef, (byte) 0xbf, (byte) 0xbd, (byte) 0x42, (byte) 0xc2, (byte) 0x9b,
(byte) 0xe6, (byte) 0x87, (byte) 0x89, (byte) 0x5a};
mTerminal.append(b, b.length);
}
public void testSimpleCombining() throws Exception {
withTerminalSized(3, 2).enterString(" a\u0302 ").assertLinesAre(" a\u0302 ", " ");
}
public void testCombiningCharacterInFirstColumn() throws Exception {
withTerminalSized(5, 3).enterString("test\r\nhi\r\n").assertLinesAre("test ", "hi ", " ");
// U+0302 is COMBINING CIRCUMFLEX ACCENT. Test case from mosh (http://mosh.mit.edu/).
withTerminalSized(5, 5).enterString("test\r\nabc\r\n\u0302\r\ndef\r\n");
assertLinesAre("test ", "abc ", " \u0302 ", "def ", " ");
}
public void testCombiningCharacterInLastColumn() throws Exception {
withTerminalSized(3, 2).enterString(" a\u0302").assertLinesAre(" a\u0302", " ");
withTerminalSized(3, 2).enterString(" à̲").assertLinesAre(" à̲", " ");
withTerminalSized(3, 2).enterString("Aà̲F").assertLinesAre("Aà̲F", " ");
}
public void testWideCharacterInLastColumn() throws Exception {
withTerminalSized(3, 2).enterString("\u0302").assertLinesAre(" ", "\u0302 ");
withTerminalSized(3, 2).enterString("").assertLinesAre("", " ").assertCursorAt(0, 2);
enterString("a").assertLinesAre("", "a ");
}
public void testWideCharacterDeletion() throws Exception {
// CSI Ps D Cursor Backward Ps Times
withTerminalSized(3, 2).enterString("\033[Da").assertLinesAre(" a ", " ");
withTerminalSized(3, 2).enterString("\033[2Da").assertLinesAre("a ", " ");
withTerminalSized(3, 2).enterString("\033[2D枝").assertLinesAre("", " ");
withTerminalSized(3, 2).enterString("\033[1D枝").assertLinesAre("", " ");
withTerminalSized(5, 2).enterString("\033[Da").assertLinesAre(" 枝a ", " ");
withTerminalSized(5, 2).enterString("a \033[D\u0302").assertLinesAre("a\u0302 ", " ");
withTerminalSized(5, 2).enterString("\033[D\u0302").assertLinesAre("\u0302 ", " ");
enterString("Z").assertLinesAre("\u0302Z ", " ");
enterString("\033[D ").assertLinesAre("\u0302 ", " ");
// Go back two columns, standing at the second half of the wide character:
enterString("\033[2DU").assertLinesAre(" U ", " ");
}
public void testWideCharOverwriting() {
withTerminalSized(3, 2).enterString("abc\033[3D枝").assertLinesAre("枝c", " ");
}
public void testOverlongUtf8Encoding() throws Exception {
// U+0020 should be encoded as 0x20, 0xc0 0xa0 is an overlong encoding
// so should be replaced with the replacement char U+FFFD.
withTerminalSized(5, 5).mTerminal.append(new byte[]{(byte) 0xc0, (byte) 0xa0, 'Y'}, 3);
assertLineIs(0, "\uFFFDY ");
}
public void testWideCharacterWithoutWrapping() throws Exception {
// With wraparound disabled. The behaviour when a wide character is output with cursor in
// the last column when autowrap is disabled is not obvious, but we expect the wide
// character to be ignored here.
withTerminalSized(3, 3).enterString("\033[?7l").enterString("枝枝枝").assertLinesAre("", " ", " ");
enterString("a枝").assertLinesAre("枝a", " ", " ");
}
}

View File

@@ -1,85 +0,0 @@
package com.termux.terminal;
import junit.framework.TestCase;
public class WcWidthTest extends TestCase {
private static void assertWidthIs(int expectedWidth, int codePoint) {
int wcWidth = WcWidth.width(codePoint);
assertEquals(expectedWidth, wcWidth);
}
public void testPrintableAscii() {
for (int i = 0x20; i <= 0x7E; i++) {
assertWidthIs(1, i);
}
}
public void testSomeWidthOne() {
assertWidthIs(1, 'å');
assertWidthIs(1, 'ä');
assertWidthIs(1, 'ö');
assertWidthIs(1, 0x23F2);
}
public void testSomeWide() {
assertWidthIs(2, '');
assertWidthIs(2, '');
assertWidthIs(2, '');
assertWidthIs(2, '中');
assertWidthIs(2, '文');
assertWidthIs(2, 0x679C);
assertWidthIs(2, 0x679D);
assertWidthIs(2, 0x2070E);
assertWidthIs(2, 0x20731);
assertWidthIs(1, 0x1F781);
}
public void testSomeNonWide() {
assertWidthIs(1, 0x1D11E);
assertWidthIs(1, 0x1D11F);
}
public void testCombining() {
assertWidthIs(0, 0x0302);
assertWidthIs(0, 0x0308);
assertWidthIs(0, 0xFE0F);
}
public void testWordJoiner() {
// https://en.wikipedia.org/wiki/Word_joiner
// The word joiner (WJ) is a code point in Unicode used to separate words when using scripts
// that do not use explicit spacing. It is encoded since Unicode version 3.2
// (released in 2002) as U+2060 WORD JOINER (HTML &#8288;).
// The word joiner does not produce any space, and prohibits a line break at its position.
assertWidthIs(0, 0x2060);
}
public void testWatch() {
}
public void testSofthyphen() {
// http://osdir.com/ml/internationalization.linux/2003-05/msg00006.html:
// "Existing implementation practice in terminals is that the SOFT HYPHEN is
// a spacing graphical character, and the purpose of my wcwidth() was to
// predict the advancement of the cursor position after a string is sent to
// a terminal. Hence, I have no choice but to keep wcwidth(SOFT HYPHEN) = 1.
// VT100-style terminals do not hyphenate."
assertWidthIs(1, 0x00AD);
}
public void testHangul() {
assertWidthIs(1, 0x11A3);
}
public void testEmojis() {
assertWidthIs(2, 0x1F428); // KOALA.
assertWidthIs(2, 0x231a); // WATCH.
assertWidthIs(2, 0x1F643); // UPSIDE-DOWN FACE (Unicode 8).
}
}