#if canImport(UIKit) import XCTest import UIKit @testable import RichTextEditorUIKit import RichTextEditorCore /// Phase 2c Task 4: dragging a `.cells` corner knob PROMOTES the focused-cell "fake" chrome (T3) to a /// committed `.cells` selection and extends it in 2D — the extend MATH + promotion (unit-testable); the raw /// gesture wiring is runtime-verified in T6. final class TableCellDragTests: XCTestCase { private func cell(_ id: String, _ text: String) -> Cell { Cell(id: BlockID(id), blocks: [.paragraph(ParagraphBlock(id: BlockID(id + "p"), runs: [TextRun(text: text)]))]) } /// A dense 3x3 table, ids "a".."i" row-major (row0: a,b,c; row1: d,e,f; row2: g,h,i). private func dense3x3() -> TableBlock { TableBlock(id: BlockID("t"), columns: [ColumnSpec(width: 100), ColumnSpec(width: 100), ColumnSpec(width: 100)], rows: [ Row(id: BlockID("r0"), cells: [cell("a", "A"), cell("b", "B"), cell("c", "C")]), Row(id: BlockID("r1"), cells: [cell("d", "D"), cell("e", "E"), cell("f", "F")]), Row(id: BlockID("r2"), cells: [cell("g", "G"), cell("h", "H"), cell("i", "I")]), ]) } /// A 3x3 table with a colspan-2 cell merged at (0,0)-(0,1) (absorbing "b"'s content into "a"'s stack). private func mergedTopLeftColspan2() -> TableBlock { dense3x3().mergingCells(in: TableRect(top: 0, left: 0, bottom: 0, right: 1)) } private func canvas(_ table: TableBlock, width: CGFloat = 390) -> DocumentCanvasView { let v = DocumentCanvasView() v.setBlocks([.table(table)], width: width) v.frame = CGRect(x: 0, y: 0, width: width, height: 600); v.layoutIfNeeded() return v } private func table(_ v: DocumentCanvasView) -> TableBlockBox { v.boxes[0] as! TableBlockBox } /// Canvas x at the MIDDLE of the physical column band `column` (span-neutral — unlike `cellRect`, which /// resolves a covered slot to its merged anchor's whole footprint). Guarantees `columnIndex(atX:)` /// resolves back to exactly `column`. private func bandMidX(_ t: TableBlockBox, column: Int) -> CGFloat { var x = t.frame.minX + TableBlockBox.border for c in 0.. CGFloat { var y = t.frame.minY + TableBlockBox.border for r in 0..