mirror of
https://github.com/ichmagmaus111/ghostgram.git
synced 2026-11-04 06:37:08 +01:00
Ghostgram for iOS, rebuilt from scratch on Telegram iOS 13.0. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
73 lines
3.8 KiB
Swift
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
|