Files
ichmagmaus111andClaude Opus 5.5 0622057a4f Ghostgram: open-source release
Ghostgram for iOS, rebuilt from scratch on Telegram iOS 13.0.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-31 17:57:09 +01:00

73 lines
3.8 KiB
Swift

#if canImport(UIKit)
import XCTest
import UIKit
@testable import RichTextEditorUIKit
import RichTextEditorCore
/// The attachment-screen table menu's "Copy Table" (`copyCurrentTable`) and "Convert to Text"
/// (`convertCurrentTableToText`) actions.
final class CanvasTableMenuActionsTests: XCTestCase {
final class FakePasteboard: TextPasteboard {
var items: [String: Any] = [:]
var string: String? {
get { items["public.utf8-plain-text"] as? String }
set { if let v = newValue { items = ["public.utf8-plain-text": v] } else { items = [:] } }
}
var hasStrings: Bool { !((string ?? "").isEmpty) }
func data(forPasteboardType type: String) -> Data? { items[type] as? Data }
func setItems(_ newItems: [[String: Any]], options: [UIPasteboard.OptionsKey: Any]) { items = newItems.first ?? [:] }
func contains(pasteboardTypes: [String]) -> Bool { pasteboardTypes.contains { items[$0] != nil } }
}
private func cell(_ id: String, _ t: String) -> Cell {
Cell(id: BlockID(id), blocks: [.paragraph(ParagraphBlock(id: BlockID(id + "p"), runs: t.isEmpty ? [] : [TextRun(text: t)]))])
}
private func canvas() -> (DocumentCanvasView, FakePasteboard) {
let v = DocumentCanvasView()
v.setBlocks([
.paragraph(ParagraphBlock(id: BlockID("top"), runs: [TextRun(text: "Top")])),
.table(TableBlock(id: BlockID("t"), columns: [ColumnSpec(width: 90), ColumnSpec(width: 90)],
rows: [Row(id: BlockID("r0"), cells: [cell("a", "a"), cell("b", "b")]),
Row(id: BlockID("r1"), cells: [cell("c", "c"), cell("d", "d")])])),
], width: 320)
v.frame = CGRect(x: 0, y: 0, width: 320, height: 600); v.layoutIfNeeded()
let pb = FakePasteboard(); v.pasteboard = pb
return (v, pb)
}
private func tableBox(_ v: DocumentCanvasView) -> TableBlockBox { v.boxes.first { $0 is TableBlockBox } as! TableBlockBox }
private func putCaretInTable(_ v: DocumentCanvasView) { let p = tableBox(v).cellTextStart(row: 0, column: 0)!; v.setSelectionForTesting(anchor: p, head: p) }
private func paraTexts(_ v: DocumentCanvasView) -> [String] {
v.currentBlocks().compactMap { if case .paragraph(let p) = $0 { return p.text } else { return nil } }
}
func test_copyCurrentTable_writesFragmentRtfAndFlattenedPlain() {
let (v, pb) = canvas()
putCaretInTable(v)
v.copyCurrentTable()
XCTAssertEqual(pb.string, "a b\nc d", "plain rep: one line per row, cells space-joined")
XCTAssertNotNil(pb.data(forPasteboardType: "public.rtf"), "RTF rep present")
let fragData = pb.data(forPasteboardType: DocumentCanvasView.richTextFragmentUTI)
XCTAssertNotNil(fragData, "app fragment present")
let frag = try! DocumentCodec.decode(fragData!)
XCTAssertEqual(frag.blocks.count, 1, "the fragment is a document with ONLY the table")
guard case .table = frag.blocks[0] else { return XCTFail("fragment carries the table (pastes back as a real table)") }
}
func test_copyCurrentTable_noopOutsideTable() {
let (v, pb) = canvas()
v.setSelectionForTesting(anchor: 0, head: 0) // caret in "Top", not the table
v.copyCurrentTable()
XCTAssertTrue(pb.items.isEmpty, "no-op when the caret isn't in a table")
}
func test_convertCurrentTableToText_replacesTableWithRowParagraphs() {
let (v, _) = canvas()
putCaretInTable(v)
v.convertCurrentTableToText()
v.layoutIfNeeded()
XCTAssertNil(v.boxes.first { $0 is TableBlockBox }, "the table is replaced")
XCTAssertEqual(paraTexts(v), ["Top", "a b", "c d"], "one body paragraph per row, cells space-joined")
XCTAssertEqual(v.head, v.boxes[1].textStart, "caret lands at the start of the first converted paragraph")
}
}
#endif