#include #include #include "CopyMode.h" namespace { CopyCursor cur(int row, int col) { return CopyCursor{.row = row, .col = col}; } // 5 rows of 10 cells (absolute rows 0..4). constexpr int kMin = 0; constexpr int kMax = 4; constexpr int kLen = 10; } // namespace class CopyModeTest : public QObject { Q_OBJECT private slots: // NOLINTBEGIN(readability-convert-member-functions-to-static) void leftClampsAtBufferStart() { const CopyCursor c = applyCopyMotion(cur(0, 0), CopyMotion::Left, 24, kMin, kMax, kLen); QCOMPARE(c.row, 0); QCOMPARE(c.col, 0); } void rightClampsAtLineEnd() { // Right at a line end wraps to the next row's start... const CopyCursor c = applyCopyMotion(cur(2, kLen - 1), CopyMotion::Right, 24, kMin, kMax, kLen); QCOMPARE(c.row, 3); QCOMPARE(c.col, 0); // ...and at the buffer's last row it clamps entirely. const CopyCursor c2 = applyCopyMotion(cur(kMax, kLen - 1), CopyMotion::Right, 24, kMin, kMax, kLen); QCOMPARE(c2.row, kMax); QCOMPARE(c2.col, kLen - 1); } void leftWrapsToPreviousRowEnd() { const CopyCursor c = applyCopyMotion(cur(3, 0), CopyMotion::Left, 24, kMin, kMax, kLen); QCOMPARE(c.row, 2); QCOMPARE(c.col, kLen - 1); } void rightWrapsToNextRowStart() { const CopyCursor c = applyCopyMotion(cur(3, kLen - 1), CopyMotion::Right, 24, kMin, kMax, kLen); QCOMPARE(c.row, 4); QCOMPARE(c.col, 0); } void upDownClampAtBufferEdges() { const CopyCursor up = applyCopyMotion(cur(0, 4), CopyMotion::Up, 24, kMin, kMax, kLen); QCOMPARE(up.row, 0); QCOMPARE(up.col, 4); const CopyCursor down = applyCopyMotion(cur(kMax, 4), CopyMotion::Down, 24, kMin, kMax, kLen); QCOMPARE(down.row, kMax); QCOMPARE(down.col, 4); } void pageMotionMovesViewportRows() { const CopyCursor up = applyCopyMotion(cur(4, 2), CopyMotion::PageUp, 3, kMin, kMax, kLen); QCOMPARE(up.row, 1); QCOMPARE(up.col, 2); const CopyCursor down = applyCopyMotion(cur(1, 2), CopyMotion::PageDown, 3, kMin, kMax, kLen); QCOMPARE(down.row, 4); // A page larger than the buffer clamps to the top. const CopyCursor big = applyCopyMotion(cur(4, 2), CopyMotion::PageUp, 99, kMin, kMax, kLen); QCOMPARE(big.row, 0); } void homeEndLandOnExpectedCells() { const CopyCursor end = applyCopyMotion(cur(2, 0), CopyMotion::LineEnd, 24, kMin, kMax, kLen); QCOMPARE(end.row, 2); QCOMPARE(end.col, kLen - 1); const CopyCursor home = applyCopyMotion(end, CopyMotion::LineHome, 24, kMin, kMax, kLen); QCOMPARE(home.row, 2); QCOMPARE(home.col, 0); } void topBottomJumpRows() { const CopyCursor top = applyCopyMotion(cur(4, 5), CopyMotion::BufferTop, 24, kMin, kMax, kLen); QCOMPARE(top.row, 0); QCOMPARE(top.col, 5); const CopyCursor bottom = applyCopyMotion(top, CopyMotion::BufferBottom, 24, kMin, kMax, kLen); QCOMPARE(bottom.row, kMax); QCOMPARE(bottom.col, 5); } void motionClampsColumnToShortRow() { // Row length 3: a column of 9 clamps to 2 on any vertical motion. const CopyCursor down = applyCopyMotion(cur(1, 9), CopyMotion::Down, 24, kMin, kMax, 3); QCOMPARE(down.row, 2); QCOMPARE(down.col, 2); // An empty row pins the column to 0. const CopyCursor empty = applyCopyMotion(cur(1, 0), CopyMotion::Down, 24, kMin, kMax, 0); QCOMPARE(empty.col, 0); } void selectionAcrossTwoRowsYanksExactText() { QVector rows; rows.append(QStringLiteral("0123456789")); rows.append(QStringLiteral("abcdefghij")); rows.append(QStringLiteral("KLMNOPQRST")); // Base row 5; select rows 6..7 (window indices 1..2), columns 3..6. CopySelection sel; sel.startRow = 6; sel.startCol = 3; sel.endRow = 7; sel.endCol = 6; sel.active = true; const QString yanked = copyYankText(rows, 5, sel); QCOMPARE(yanked, QStringLiteral("defg\nNOPQ")); // Single-cell selection: one character, no newline. CopySelection one = sel; one.endRow = one.startRow; one.endCol = one.startCol; QCOMPARE(copyYankText(rows, 5, one), QStringLiteral("d")); } void selectionReversedAnchorNormalizes() { // Anchor right of/below head: normalization flips to reading order. const CopySelection sel = normalizeCopySelection(cur(7, 9), cur(6, 3)); QVERIFY(sel.active); QCOMPARE(sel.startRow, 6); QCOMPARE(sel.startCol, 3); QCOMPARE(sel.endRow, 7); QCOMPARE(sel.endCol, 9); // Same row, reversed columns. const CopySelection sameRow = normalizeCopySelection(cur(2, 8), cur(2, 4)); QCOMPARE(sameRow.startRow, 2); QCOMPARE(sameRow.startCol, 4); QCOMPARE(sameRow.endCol, 8); } void selectionSpanningCaptureWindowPads() { // Selection reaching past the captured window pads with spaces. QVector rows; rows.append(QStringLiteral("ab")); CopySelection sel; sel.startRow = 10; // bufferBaseRow 10 -> window row 0 sel.startCol = 0; sel.endRow = 11; // outside the window (1 row captured) sel.endCol = 4; sel.active = true; QCOMPARE(copyYankText(rows, 10, sel), QStringLiteral("ab \n ")); } // NOLINTEND(readability-convert-member-functions-to-static) }; QTEST_MAIN(CopyModeTest) #include "tst_copymode.moc"