Testing Terminal Resize Operations in Termux App
This test suite validates terminal resizing functionality in the Termux terminal emulator, focusing on buffer handling, character display, and cursor positioning. The tests ensure proper terminal behavior during dynamic size adjustments while maintaining text content integrity and visual formatting.
Test Coverage Overview
Implementation Analysis
Technical Details
Best Practices Demonstrated
termux/termux-app
terminal-emulator/src/test/java/com/termux/terminal/ResizeTest.java
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 ", " ");
resize(cols, 2);
assertLinesAre("999 ", " ");
resize(cols, 5);
assertLinesAre("996 ", "997 ", "998 ", "999 ", " ");
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("QR").assertLinesAre("QR ", " ", " ", " ");
resize(2, rows).assertLinesAre("Q", "R", " ", " ");
resize(5, rows).assertLinesAre("QR ", " ", " ", " ");
}
}